Local development
Local web development against deployed development or production services.
Prerequisites
- Node.js 22+
- pnpm 10+
Default Mode
Local web development uses the deployed dev backend by default:
| App origin | Auth origin | API origin |
|---|---|---|
http://localhost:<port> | https://auth.todayai.dev | https://api.todayai.dev |
Run from the repo root:
pnpm install
cp apps/web/.env.development.local.example apps/web/.env.development.local
# fill in OIDC client_id + secret
pnpm devapps/web/scripts/dev-server.mts scans 4060-4069 for the first free port, so
multiple worktrees can run side by side.
The app no longer supports routing the web frontend to a locally running backend. Backend work should use the deployed dev backend contract or test backend changes inside the backend repo.
Production Backend
Run from the repo root or apps/web:
| Command | Auth origin | API origin |
|---|---|---|
pnpm dev:prod | https://auth.today.ai | https://api.today.ai |
pnpm dev:prod:cn | https://auth.todayai.cn | https://api.todayai.cn |
Both commands keep Next.js in development mode with local hot reload and the
same automatic 4060-4069 port selection. Open the printed localhost URL and
use /login to sign in to the selected production service.
The launcher sets production API/auth URLs, token audience and localhost auth
proxy settings before preparing the app and browser adapter. It disables MSW
and clears the configured traffic lane. These settings override existing dev
URLs in .env.development.local without rewriting that file. The canonical app
URL points to the production site, so external app links (including the CN
downloads page's login link) still point there.
Existing local credential loading is unchanged. When debugging legacy OIDC
flows, supply the selected production environment's matching
NEXT_PUBLIC_OIDC_CLIENT_ID and OIDC_CLIENT_SECRET through your shell or
.env.development.local; these commands do not fetch or replace credentials.
Local analytics continues to use the development configuration.
Microfrontends Mode
Use the Microfrontends proxy when developing the composed Web and Embed experience.
Open http://localhost:3024 rather than an individual Next.js server port.
| Command | Local applications | Production fallback |
|---|---|---|
pnpm dev:mfe | Web and Embed | None |
pnpm dev:mfe:web | Web | Embed |
pnpm dev:mfe:embed | Embed | Web |
The partial modes only pass the server they start to --local-apps. Requests for
the other application use the today.ai fallback declared in
apps/web/microfrontends.json. Do not start one server with the all-local command:
an application declared local is expected to be listening on its configured port
and will not fall back automatically.
Auth On Localhost
LOCALHOST_BFF=true is committed in apps/web/.env.development. The auth BFF
route (/api/auth/*) relays calls to the selected auth service and strips the
Domain attribute from better-auth session cookies before returning them to the
browser. That lets localhost store a host-only session cookie.
When local development targets a regional auth service whose trusted browser
origin differs from the default localhost origin, set the server-only
LOCALHOST_AUTH_ORIGIN override in .env.development.local. For example, the
China environment uses LOCALHOST_AUTH_ORIGIN=https://todayai.cn. The BFF only
applies this override after verifying that the incoming request is same-origin
HTTP localhost traffic.
The flag is server-only and Next only loads .env.development under
NODE_ENV=development, so production builds never see it.
Cookie scope is per-host, not per-port. Two worktrees on different localhost ports share one browser cookie jar. Use a separate browser profile or isolated automation context when you need two logged-in worktrees simultaneously.
Env Files
Next.js loads env files in this order during next dev:
| Priority | File | Committed | Purpose |
|---|---|---|---|
| 1 (highest) | .env.development.local | No | Credentials + optional dev overrides |
| 2 | .env.development | Yes | Dev backend defaults |
| 3 (lowest) | .env | Yes | Shared defaults (rarely used) |
Full env-var mechanics are in Architecture → Environment variables.
Getting Credentials
cd apps/web
vercel link
vercel env pull .env.development.local --environment previewKeep the OIDC client id and secret. URL values should point at
auth.todayai.dev, api.todayai.dev, and todayai.dev.
Troubleshooting
"OIDC client_id not configured"
.env.development.local is missing or does not have
NEXT_PUBLIC_OIDC_CLIENT_ID.
502 on auth API calls
The BFF route cannot reach the auth server. For local web dev,
OIDC_INTERNAL_AUTHORITY should be https://auth.todayai.dev.
"invalid_client" error
The OIDC client id or secret is wrong, or the client does not exist in the dev auth backend. Re-pull preview env from Vercel.
Stuck on the login redirect
Stale OIDC state. DevTools → Application → Local Storage → delete every key
starting with oidc., then refresh.
MSW handlers and fixtures
MSW (Mock Service Worker) is the mock-mode runtime — handlers + fixtures live under `apps/web/src/lib/msw/` and are also the source of truth for Storybook stories that need network responses.
Parallel worktrees
Run multiple branches in parallel via `git worktree add`. What env files to mirror, the cookie-jar caveat, and the future per-worktree hostname plan.