Installation
Run the TanStack + Convex starter locally with the Convex local backend, Convex Auth, the web app and the admin app.
This page takes you from a fresh clone to a signed-in account with a workspace, plus the admin app running on its own port. The whole flow runs on your computer; no Convex account or Docker is needed.
The shared getting started page covers the parts that are the same for every kit.
Clone the repository
git clone https://github.com/usenextbase/tanstack-convex-starter.git
cd tanstack-convex-starterIf GitHub says the repository doesn't exist, check that you are signed in with the account that has access.
Install dependencies
Use Node.js 24 (the version in .nvmrc; package.json engines requires >=24) and let corepack select pnpm 10.33.0 from the packageManager field.
corepack enable
pnpm installCreate and select the local Convex backend
Copy the example env file first, then create and select the local deployment:
cp .env.local.example .env.local
pnpm db:local:init
pnpm db:local:selectdb:local:init runs convex init with CONVEX_AGENT_MODE=anonymous, so no Convex login is needed. db:local:select runs convex deployment select local and fills in CONVEX_DEPLOYMENT, VITE_CONVEX_URL and CONVEX_SITE_URL in .env.local at the repository root. The backend state (rows, storage, schedules, function execution) lives in .convex/, which is gitignored.
Copying the example file first matters. When .env.local already contains a VITE_CONVEX_URL line, the CLI updates it. When the file does not exist, the CLI creates it with CONVEX_URL instead, because Vite is not a root dependency, and you have to add VITE_CONVEX_URL yourself. The dev:local guard accepts either name for its loopback check, but stops with a message telling you to add VITE_CONVEX_URL=http://127.0.0.1:3210 if only CONVEX_URL is present, because the web app reads the VITE_ name.
After the select step, the first lines of .env.local should look like this:
CONVEX_DEPLOYMENT=local:nextbase
VITE_CONVEX_URL=http://127.0.0.1:3210
CONVEX_SITE_URL=http://127.0.0.1:3211
APP_URL=http://localhost:3000APP_URL is never generated; it comes from the example file. The example also sets VITE_ADMIN_APP_URL=http://localhost:3002 for the admin app link and MCP_APP_URL=http://localhost:3000 for the MCP consent page.
Don't copy the example file over an existing .env.local
.env.local.example documents every variable, but the Convex CLI maintains the deployment lines in .env.local. Copy the example only when you have no .env.local yet, and keep your own values if you already have one.
Configure the admin app
The admin app has its own env file because apps/admin/vite.config.ts sets envDir: ".". Copy its example and point it at the local backend:
cp apps/admin/.env.local.example apps/admin/.env.localVITE_CONVEX_URL=http://127.0.0.1:3210
VITE_WEB_APP_URL=http://localhost:3000
VITE_OAUTH_PROVIDERS=The example ships with a cloud placeholder for VITE_CONVEX_URL; replace it with the same local URL the web app uses. VITE_WEB_APP_URL is where impersonation handoffs and the "Open web app" link go.
Set up Convex Auth
pnpm auth:setupThis runs the @convex-dev/auth CLI against the selected deployment. It configures the auth signing keys (JWT_PRIVATE_KEY and JWKS) and SITE_URL in that deployment's environment. Password sign-in works after this step. Run it again if you create a new local deployment.
So the admin app can sign in on its own origin, also set the admin origin in the local deployment:
pnpm convex env set ADMIN_SITE_URL http://localhost:3002Start the dev servers
pnpm dev:localdev:local runs the guard, then starts four processes with concurrently: convex dev (local backend on http://127.0.0.1:3210, HTTP actions on http://127.0.0.1:3211), the web app, the admin app and the React Email preview server.
| App | URL |
|---|---|
| Web app | http://localhost:3000 (apps/web/vite.config.ts) |
| Email template preview | http://localhost:3001 |
| Admin app | http://localhost:3002 (apps/admin/vite.config.ts); / redirects to /app-admin |
To run only the admin app, use pnpm dev:admin. Keep the Convex process running while you use either app.
Seed reference data (optional)
In a second terminal:
pnpm db:seedThis runs dev/seed:seed, which inserts the product row in appSettings (product name and support email) once. It is idempotent.
Create your account and workspace
Open http://localhost:3000/sign-up and create an account with a name, email and password. The kit then sends a verification code and takes you to /update-password?mode=verify to enter it.
There is no local email inbox
Verification, password reset and magic link emails go through Resend even in local development. Set AUTH_RESEND_KEY and AUTH_EMAIL_FROM in the local deployment with pnpm convex env set NAME value to receive them. Without them, use a social provider you have configured, or see the authentication page for what works without email.
After signing in you land on /onboarding, complete your profile and create a workspace. Then add a project from the workspace's projects page so you have data to test with.
Verify the setup
Run the quality gates from the repository root:
pnpm format:check
pnpm lint
pnpm typecheck
pnpm test
pnpm buildpnpm test runs Vitest in each workspace (Convex functions use convex-test). pnpm test:e2e runs Playwright against http://127.0.0.1:3000; without PLAYWRIGHT_BASE_URL it starts its own local Convex backend and web server. Install the browser first with pnpm --filter @nextbase/web exec playwright install --with-deps chromium.
Make yourself an application admin
Set the admin email in the local deployment, sign in with that address on the admin app at http://localhost:3002, then use Claim admin access on /app-admin:
pnpm convex env set NEXTBASE_ADMIN_EMAIL admin@example.comThe admin app has its own login page and session; signing in to the web app does not sign you in to the admin app. The authentication page explains the claim flow.
Useful commands
| Command | What it does |
|---|---|
pnpm dev | Same as dev:local but without the local-deployment guard |
pnpm dev:admin | Starts only the admin app on port 3002 |
pnpm build:web, pnpm build:admin | Build one frontend without Turbo |
pnpm db:codegen | Regenerates apps/database/convex/_generated |
pnpm db:types | Regenerates apps/database/lib/database.types.ts from the schema validators |
pnpm db:status | Opens the Convex dashboard for the selected deployment |
pnpm agents:sync | Regenerates the AI coding tool files from AGENTS.md and .agents/; CI runs pnpm agents:check |
pnpm convex run migrations:backfillUsersAggregate | One-time backfill of the users aggregate when upgrading an existing deployment |
Stop and reset
Stop the dev servers with Ctrl+C; concurrently stops the other processes when one exits. The local data in .convex/ is kept between runs.
To reset the local backend, stop the servers and delete the .convex/ directory, then run pnpm db:local:init, pnpm db:local:select and pnpm auth:setup again. Deleting .convex/ removes every local row, upload and scheduled job, including the deployment environment variables you set with pnpm convex env set.
If a request fails after a branch change, check that convex dev is still running and that .env.local points at the local deployment. See troubleshooting.