Nextbase Docs
Nextbase Docs
HomeBlogWelcome to Nextbase v5!Choose your starterGetting startedLocal Supabase per agent
Next.js + Cloudflare D1InstallationEnvironment variablesAuthenticationAgent connectionsProject structureDeployment
AuthenticationWorkspaces and the admin area
Building with agentsEmails with Resend
TroubleshootingNextbase v5
The 8 starter kitsNext.js + Cloudflare D1

Installation

Clone the Next.js + Cloudflare D1 starter, create the local D1 databases and run the web app, the admin app and the platform Worker on your machine.

Local development doesn't need a Cloudflare account. Wrangler keeps local D1 databases, R2 buckets, queues and Durable Objects under apps/web/.wrangler/state, and the platform Worker reads from that same directory.

Use Node.js 24 and the pnpm version in the repository's package.json (pnpm@11.1.2). Docker is optional and only used for the Mailpit inbox.

Clone the kit

git clone https://github.com/usenextbase/nextjs-cloudflare-d1-starter.git
cd nextjs-cloudflare-d1-starter

If GitHub says the repository doesn't exist, check that you are signed in with the account that has access.

Install dependencies

corepack enable
pnpm install

pnpm install runs fumadocs-mdx in apps/web as a postinstall step. The lockfile also applies a patch to @opennextjs/aws from patches/; that happens automatically.

Create the env files

Create each file only when it is missing. Never overwrite a file you already customized.

[ -f apps/web/.dev.vars ] || cp apps/web/.dev.vars.example apps/web/.dev.vars
[ -f apps/platform-worker/.dev.vars ] || cp apps/platform-worker/.dev.vars.example apps/platform-worker/.dev.vars
[ -f apps/admin/.dev.vars ] || cp apps/admin/.dev.vars.example apps/admin/.dev.vars
[ -f apps/web/.env.local ] || cp apps/web/.env.local.example apps/web/.env.local

The .dev.vars files hold Worker secrets. Non-secret local defaults such as BETTER_AUTH_URL, NEXT_PUBLIC_SITE_URL, ADMIN_EMAIL, USE_LOCAL_EMAIL and MAILPIT_API_URL are already set in the vars block of apps/web/wrangler.jsonc, apps/admin/wrangler.jsonc and apps/platform-worker/wrangler.jsonc. apps/web/.env.local only holds the optional public analytics and Sentry build variables.

Two values need attention before the app runs well:

  • REALTIME_TOKEN_SECRET must be the exact same value of at least 32 characters in the web, admin and platform .dev.vars files.
  • INTERNAL_SERVICE_SECRET in the platform Worker must be an independent value of at least 32 characters.

The admin app can keep its own BETTER_AUTH_SECRET; its cookies use a different prefix, so the two sign-ins stay independent. The full list is in environment variables.

Start Mailpit (optional)

pnpm infra:start
pnpm infra:wait

This runs docker compose up -d mailpit and waits for http://localhost:8025/livez. The inbox is at http://localhost:8025 and SMTP listens on port 1025. Override the ports with MAILPIT_SMTP_PORT and MAILPIT_HTTP_PORT in your shell if they clash.

Without Mailpit, auth emails are written to the D1 outbox and stay pending. Sign-up doesn't fail; you just can't open the verification link. Use the seeded accounts in the next step instead.

Migrate and seed the local databases

pnpm db:migrate
pnpm db:seed

pnpm db:migrate applies the application migrations from apps/database/migrations to the APP_DB binding and the OpenNext cache migration from apps/web/cache-migrations to NEXT_TAG_CACHE_D1. Both run against local Wrangler databases using apps/web/wrangler.jsonc. The admin app points at the same local database names, so it needs no separate migration step.

pnpm db:seed executes apps/database/seed.sql against the local APP_DB. It is idempotent and creates verified local-only accounts, so you can sign in without an email provider. The app-admin account is admin@example.com with password password123. Alice, Bob and Carol are at alice@demo.nextbase.local, bob@demo.nextbase.local and carol@demo.nextbase.local with the same password. Never reuse these credentials outside local development.

Start the dev servers

pnpm dev

Turborepo runs every workspace dev script in parallel:

ProcessAddress
Next.js dev server (apps/web)http://localhost:3000
Admin app (apps/admin, next dev -p 3001)http://localhost:3001
Platform Worker through wrangler dev (apps/platform-worker)http://127.0.0.1:8788, health check at /health
React Email preview (apps/email)http://localhost:3001

The admin app and the email preview both default to port 3001

apps/admin and apps/email each declare port 3001, so under pnpm dev only one of them gets it. When you need the admin app, run the processes separately: pnpm web#dev, pnpm worker:dev and pnpm admin:dev in three terminals, and start the email preview with pnpm --filter @nextbase/email dev only when you work on templates. NEXT_PUBLIC_ADMIN_APP_URL in apps/web/wrangler.jsonc and NEXT_PUBLIC_WEB_APP_URL in apps/admin/wrangler.jsonc already point the two apps at each other on ports 3000 and 3001.

Both Next.js apps read their Worker bindings and .dev.vars through initOpenNextCloudflareForDev() in their next.config.ts, so getCloudflareContext() works in development. The platform Worker script also polls /__scheduled every two seconds so the outbox cron behaves like production. Change the Worker port with PLATFORM_WORKER_PORT.

Sign up and create a workspace

Open http://localhost:3000. Either sign in with a seeded account or sign up with a new email. New accounts must verify their email; open the message in Mailpit when it is running.

Complete onboarding and create a workspace. Add a project through the website so you have data to try with an agent later. If you sign up with the ADMIN_EMAIL configured in the Wrangler vars (admin@example.com by default), that account receives the application-admin role.

To use the admin area, open http://localhost:3001 and sign in again with the admin account. The admin app has its own login page and its own session cookie; a non-admin account gets a 403 there.

Verify the setup

pnpm verify:local

This runs the legacy-reference scan, the Drizzle journal and schema drift checks, generated-type checks, local migrations, lint, typecheck, unit tests and an OpenNext Worker build. The Playwright suite builds the admin and web Workers and prepares local D1 on its own:

pnpm test-integration

For a production-runtime check in workerd, run pnpm cf:preview. It builds all three Workers with pnpm cf:build and starts the platform Worker and the web Worker locally with opennextjs-cloudflare preview.

One-command setup

./setup.sh runs the same flow: install, copy apps/web/.dev.vars, apps/platform-worker/.dev.vars and apps/web/.env.local from their examples when missing, start Mailpit if Docker is available, migrate, seed and pnpm verify:local. It doesn't create apps/admin/.dev.vars; copy that one yourself before starting the admin app.

Stop and reset

Press Ctrl-C to stop pnpm dev. Stop Mailpit with pnpm infra:stop; pnpm infra:status shows whether it is running.

To clear the local D1 databases and re-apply migrations:

pnpm db:reset
pnpm db:seed

db:reset deletes only apps/web/.wrangler/state/v3/d1, so local R2 objects and Durable Object state are kept. Delete apps/web/.wrangler entirely if you want a completely fresh local Cloudflare state.

Other local tools

  • pnpm db:studio opens Drizzle Studio against the local SQLite file.
  • pnpm admin:dev runs only the admin app; pnpm web#dev runs only the web app; pnpm worker:dev runs only the platform Worker.
  • pnpm --filter @nextbase/email dev runs only the email preview.
  • stripe listen --forward-to localhost:3000/api/stripe/webhooks forwards Stripe webhooks; copy the printed whsec_ value into STRIPE_WEBHOOK_SECRET in apps/web/.dev.vars and restart the web app.

Next.js + Cloudflare D1

What the Next.js + Cloudflare D1 starter includes, what you need before you start, and where to go next.

Environment variables

Every variable in the Next.js + Cloudflare D1 starter's example files, which Worker reads it, and where the value comes from.

On this page

Clone the kitInstall dependenciesCreate the env filesStart Mailpit (optional)Migrate and seed the local databasesStart the dev serversSign up and create a workspaceVerify the setupOne-command setupStop and resetOther local tools