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

Project structure

The Next.js + Neon monorepo at a glance and where to make changes for routes, the admin app, data, schema, auth, emails, jobs, MCP and tests.

The kit is a pnpm workspace with Turborepo. Four apps and one shared package live under apps/ and packages/. Everything is TypeScript, formatted with Prettier and linted with oxlint.

The tree

proxy.ts
typed-cache-tags.ts
.env.test
next.config.ts
package.json
.env.local.example
next.config.ts
package.json
tsconfig.json
docker-compose.yml
drizzle.config.ts
.env.example
AGENTS.md
package.json
pnpm-workspace.yaml
turbo.json
PackageNameWhat it is
apps/webwebThe customer Next.js 16 app on port 3000: marketing pages, auth, workspaces and projects, server actions, domain logic, the User MCP, CLIs and Playwright tests
apps/adminadminThe administrator Next.js 16 app on port 3001: admin sign-in, the /app-admin panel, feedback and roadmap moderation, the Admin MCP and the impersonation handoff
apps/databasedatabaseDrizzle schema, Postgres migrations, migrate and seed scripts, generated types, the Docker Compose stack
apps/emailemailReact Email templates and the render helpers the web app imports
packages/typescript-configShared tsconfig.base.json

apps/database/drizzle/ holds the historical MySQL migrations from the PlanetScale version. They are never applied; leave them alone.

How the admin app shares code

apps/admin/tsconfig.json maps @/* to ./src/* first and ../web/src/* second, so an import such as @/lib/auth/session or @/components/ui/button resolves to the web app's file unless the admin app has its own copy. The admin app therefore has no lib/, no rsc-data/ and only a handful of components; everything it owns is routes under src/app/, administrative queries and actions under src/data/admin/, and the admin sidebar and breadcrumbs under src/components/. Its next.config.ts sets the Turbopack root to the repository so those cross-app imports compile. Keep customer-facing code in apps/web; put administrative mutations only in apps/admin.

Where to make changes

Routes and pages

  • Public marketing pages: apps/web/src/app/(external-pages)/. Nav links are in components/navigation-menu/external-navbar/constants.ts.
  • Signed-in customer area: apps/web/src/app/(dynamic-pages)/(authenticated-pages)/. Workspace pages sit under (application-pages)/workspace/[workspaceSlug]/, project pages under (application-pages)/project/[projectSlug]/, and account settings under user/. Workspace pages have parallel @navbar and @sidebar slots with default.tsx fallbacks.
  • Auth pages: (login-pages) and (misc-login-pages). Public feedback and roadmap: (updates-pages). The impersonation landing page is apps/web/src/app/auth/impersonation/page.tsx.
  • Admin panel: apps/admin/src/app/(dynamic-pages)/(authenticated-pages)/app-admin/(admin-pages)/ with users, workspaces, settings, payment-gateway and marketing/{authors,blog,tags,changelog}, plus @navbar and @sidebar slots. Feedback moderation is apps/admin/src/app/feedback/, roadmap moderation apps/admin/src/app/roadmap/, and the admin sign-in page apps/admin/src/app/login/page.tsx.
  • Route handlers: apps/web/src/app/api/. Better Auth is at api/auth/[...all] (and again in the admin app), the Stripe webhook at api/stripe/webhooks, uploads under api/storage/uploads, the realtime token at api/realtime/token, the impersonation redemption at api/impersonation, and the cache refresh the admin app calls at api/internal/admin-revalidate. The admin app adds api/admin/marketing/media for CMS uploads.
  • Sidebar links: apps/web/src/components/sidebar-workspace-nav.tsx and sidebar-platform-nav.tsx in the web app; apps/web/src/components/sidebar-admin-panel-nav.tsx renders the Open admin panel link; apps/admin/src/components/sidebar-admin-panel-nav.tsx is the admin app's menu.

A page exports metadata, awaits params, parses them with zod from utils/zod-schemas/params.ts, and wraps dynamic content in <Suspense>. cacheComponents is on in both apps, so cached reads use "use cache" with tags from typed-cache-tags.ts. Admin data must stay live and permission-scoped; never prerender it into public caches.

Server and data access

  • apps/web/src/data/{anon,user}/ and apps/admin/src/data/admin/ are "use server" modules with queries and next-cool-action actions. authActionClient and adminActionClient come from apps/web/src/lib/safe-action.ts.
  • apps/web/src/rsc-data/ wraps those queries with React cache() for server components, for example getCachedWorkspaceBySlug.
  • Reusable rules live in lib/domain/ (policies with tests, events.ts for audit and outbox rows) and lib/services/.
  • Admin mutations that change public content call refreshWebAfterAdminMutation from apps/web/src/lib/admin-revalidation.ts so the web app revalidates.
  • Import db, pool, schema and newId from the database package. Don't create new pools.

Schema and migrations

  • Edit apps/database/src/schema.ts, then pnpm db:generate, review the SQL in apps/database/drizzle-postgres/, pnpm db:check-migrations, pnpm db:migrate, pnpm gen-types, update the seeds, then pnpm db:verify-clean.
  • Migrations are additive and must replay on an empty database. Never edit an applied migration or its snapshot.
  • Seeds: apps/database/src/seed.ts (minimal) and apps/web/src/cli/seed.ts (full fixtures). Both must stay idempotent.
  • The db-migration skill in .agents/skills/db-migration/SKILL.md describes the whole loop.

Authentication

apps/web/src/lib/auth/ holds the Better Auth server and client, session helpers, actors, workspace permissions and the impersonation handoff helpers. The admin app reuses all of it. See authentication.

Emails

Templates are in apps/email/emails/*.tsx. Add a render helper in apps/email/src/index.tsx and a render test, then send through apps/web/src/lib/email/send-email.ts. Preview templates with pnpm --filter email dev; the preview server defaults to port 3001, the same port as the admin app, so pass another port when both are running.

Background jobs

There are no queues. Mutations write to outbox_events, and apps/web/src/cli/dispatch-outbox.ts claims batches of 50 and publishes them to Centrifugo (pnpm realtime:dispatch, or realtime:dispatch:once for a single pass). apps/web/src/cli/cleanup-storage.ts removes expired unattached uploads. Realtime helpers are in lib/realtime/, storage in lib/storage/uploads.ts and lib/storage/provider.ts.

MCP

apps/web/src/mcp/ holds the implementation. The web app mounts it for the user audience in app/mcp, app/oauth and app/.well-known; the admin app mounts the same handler for the admin audience in its own app/mcp, app/oauth and app/.well-known. See agent connections.

Tests

  • Unit tests sit next to the code as *.test.ts(x) and run with pnpm test (Vitest). Tests for the shared auth code and the handoff routes live in apps/web, including apps/web/src/app/api/impersonation/route.test.ts.
  • Integration tests are in apps/web/src/integration/*.integration.test.ts and need the Docker stack: pnpm test:integration.
  • Playwright specs are in apps/web/e2e/ (anon, user, admin, invitations, lifecycle, password-updation, visual, with _helpers and _setups), configured in apps/web/playwright/playwright.config.mts. The config builds both apps and starts the web app on port 3100 with apps/web/.env.test and the admin app on port 3101; the admin project and the admin setup run against the admin origin.
  • Repository gates: scripts/check-provider-purity.mjs, scripts/check-postgres-migrations.mjs, scripts/verify-clean-migrations.sh and scripts/check-ultimate-parity.mjs, all run by pnpm verify:local and in .github/workflows/ci.yml.

AI coding tool configuration

Edit only AGENTS.md (root and per app, including apps/admin/AGENTS.md), .agents/config.json and .agents/skills/, then run pnpm agents:sync. CLAUDE.md, GEMINI.md, .mcp.json, .cursor/, .vscode/mcp.json and the other tool files are generated, and CI runs pnpm agents:check to catch drift.

Agent connections

The User MCP and Admin MCP servers in the Next.js + Neon starter: endpoints on the web and admin origins, tools, OAuth behaviour and how to add a tool.

Deployment

Put the Next.js + Neon starter in production: a Neon database, migrations, two Vercel projects for the web and admin apps, and post-deploy checks.

On this page

The treeHow the admin app shares codeWhere to make changesRoutes and pagesServer and data accessSchema and migrationsAuthenticationEmailsBackground jobsMCPTestsAI coding tool configuration