Build product integrations with AI.
Use `npm` as the project package manager.
After running the initial `npm install` or `npm ci`, run `npm run prepare` to install Husky git hooks.
## Linting & formatting
Linting uses **oxlint** โ `npm run lint` (and `npm run lint:fix`), configured in `.oxlintrc.json`. Type-aware rules run via `oxlint-tsgolint`, which resolves types from source, so no `ts-build`/`dist` is needed first. Formatting is **Prettier** โ `npm run format` (CI checks it via `npm run format:check`).
For inline editor diagnostics, install the oxlint extension: VS Code / Cursor โ `oxc.oxc-vscode`; JetBrains โ the `oxc` plugin; Neovim/Emacs/Helix/Sublime โ any LSP client via `oxlint --lsp`. The ESLint extension will no longer show diagnostics.
## Product analytics
Every analytics event the webapp, server or CLI sends is defined in `packages/types/lib/analytics/catalogue.ts`. To add, rename or remove one, use the `managing-analytics-events` skill.
## Running Nango locally
For full local dev setup (Docker, service URLs, auth flows, troubleshooting), use the `running-and-testing-locally` skill.
## Running the webapp dev server
### Multiple worktrees (local backend)
Run `npm run dev -w packages/webapp` from each worktree. Vite picks the next free port (3000 โ 3001 โ 3002 โฆ) and each dashboard calls the local backend at `localhost:3003` directly โ the API's dev CORS trusts any `localhost` port, so no proxy or `apiUrl` rewrite is needed. Only `/env.js` is proxied so `window._env` loads same-origin.
### Remote API
Pass `REMOTE_API=<env>` to proxy all API traffic to a live backend instead. No local backend needed.
```bash
REMOTE_API=dev npm run dev -w packages/webapp # https://api-development.nango.dev
REMOTE_API=staging npm run dev -w packages/webapp # https://api-staging.nango.dev
REMOTE_API=prod npm run dev -w packages/webapp # https://api.nango.dev
```
## Design system
`@nangohq/design-system` components (`Button`, `IconButton`, โฆ) own their styling. In any package that consumes the design system (webapp, โฆ), **don't override it with `className` or `style`** โ a lint rule (`react/forbid-component-props`) flags these props where the design system is used. Instead:
- Use the component's `variant`/`size` and other props.
- Put layout (margin, positioning, width) on a **wrapper element**, not the component.
- Need a look no prop covers? Add a variant to the design system โ see `packages/design-system/AGENTS.md`.
Full guidance: `packages/design-system/stories/StylingAndCustomization.mdx`