Production-focused Next.js starter for open-source apps and internal products. One app, one production runtime, auth included, and conventions that stay boring on purpose.
Created by Chahat Kesharwani · Portfolio · GitHub · Repository
- Next.js 16 App Router with TypeScript and Tailwind CSS 4
- Auth out of the box — signup, login, signed session cookies, role-based redirects
- PostgreSQL + Prisma 7 in a workspace package with migrations and admin seeding
- Centralized copy —
AppStringsandAppErrorsinpackages/shared/ - SOPS + age encrypted secrets for local and production env files
- Docker local database and production image/compose contracts
- GitHub Actions CI, production deploy workflow, labels, and governance templates
- Claude Code skills, agents, and repo guardrails under
.claude/
git clone https://github.com/chahatkesh/dev-starter.git
cd dev-starter
pnpm install
cp .env.example .envSet at minimum in .env:
| Variable | Purpose |
|---|---|
AUTH_SECRET |
Signs login session cookies (32+ random characters) |
ADMIN_EMAIL |
Email for the seeded admin account |
ADMIN_PASSWORD |
Password for the seeded admin account |
DATABASE_URL |
PostgreSQL connection string |
age-keygen -o .age-key.txt
chmod 600 .age-key.txt
# Copy the public key into .sops.yaml, then:
export SOPS_AGE_KEY_FILE="$PWD/.age-key.txt"
pnpm secrets:decryptpnpm docker:dev # start local PostgreSQL
pnpm db:migrate # apply migrations
pnpm db:seed # seed admin from ADMIN_EMAIL / ADMIN_PASSWORDDatabase package scripts load env from the repo-root .env.
pnpm dev:procs # database + Next.js + Prisma Studio (manual)
# or
pnpm devOpen http://localhost:3000.
| Route | Who | After login |
|---|---|---|
/signup |
New users | Redirects to /app |
/login |
Everyone | Admin → /admin, user → /app |
/app |
Standard users | Protected workspace |
/admin |
Admin role | Protected admin dashboard |
/api/health |
Deploy checks | Public JSON health contract |
dev-starter/
├── app/ # Next.js App Router (pages, layouts, API routes, server actions)
│ ├── admin/ # Admin dashboard (ADMIN role)
│ ├── app/ # User workspace (authenticated users)
│ ├── (auth)/ # Route group for public auth pages
│ │ ├── login/ # Sign-in form + server action
│ │ └── signup/ # Sign-up form + server action
│ └── api/health/ # Production health endpoint
├── components/ # Reusable React components
│ ├── auth/ # Auth shell, fields, logout button
│ ├── marketing/ # Creator attribution footer
│ └── ui/ # Button, Input, Card, PageShell, TextLink
├── hooks/ # Client-side React hooks
├── lib/ # Shared server/browser utilities
│ └── auth/ # Sessions, passwords, constants, sign-out action
├── services/ # Business logic (auth-service, etc.)
├── workers/ # Long-running daemon entrypoints (placeholder)
├── scripts/ # One-shot operational scripts
├── packages/
│ ├── database/ # Prisma schema, migrations, seed, client export
│ └── shared/ # AppStrings + AppErrors (framework-free)
├── tests/
│ └── unit/
│ ├── app/ # Root app tests
│ └── packages/ # database, shared package tests
├── infrastructure/
│ ├── docker/ # docker-compose dev + prod
│ ├── dockerfiles/ # Production Dockerfile
│ └── nginx/ # Reverse proxy template
├── secrets/ # SOPS-encrypted env files (committed)
├── docs/ # Engineering docs
├── .claude/ # Claude Code agents, skills, rules, hooks
├── .github/ # CI/CD, labels, issue templates, CODEOWNERS
├── proxy.ts # Route protection + role redirects (Next.js proxy)
├── mprocs.yaml # Local process supervisor config
├── Makefile # SOPS decrypt/edit helpers
└── .env.example # Non-secret runtime contract
| Layer | Location | Responsibility |
|---|---|---|
| UI & routes | app/, components/ |
Compose pages, forms, layouts; delegate to services |
| Business logic | services/ |
Auth, DB workflows, external APIs |
| Shared utilities | lib/ |
Env, logging, auth helpers, worker utils |
| Copy & errors | packages/shared/ |
AppStrings (UI copy), AppErrors (service/API errors) |
| Database | packages/database/ |
Prisma schema, migrations, seed, client |
| Protection | proxy.ts |
Guards /admin, /app; redirects logged-in users from auth pages |
Import paths:
@/*— repo root@shared/app-strings— user-facing copy@shared/app-errors— reusable errors
All reusable user-facing copy lives in packages/shared/src/app-strings/index.ts. Do not hardcode strings in components, pages, or services.
import { AppStrings } from "@shared/app-strings";
<h1>{AppStrings.auth.signInTitle}</h1>Service and validation errors use AppErrors:
import { AppErrors } from "@shared/app-errors";
throw AppErrors.create(AppErrors.invalidCredentials);Add new strings and errors to packages/shared/ before using them in app code. See packages/shared/AGENTS.md.
Reusable primitives live in components/ui/:
| Component | Use case |
|---|---|
Button |
Form submits, actions, disabled/loading state |
ButtonLink |
Navigation styled as a button |
Input |
Text, email, password fields |
Field |
Label + input wrapper |
Card |
Bordered content panels |
Alert |
Inline error messages |
TextLink |
Internal routes and external links |
PageShell |
Shared page layout with optional footer |
Feature-specific composition stays in folders like components/auth/ and components/marketing/. Pages should import primitives instead of duplicating Tailwind classes.
Creator links are centralized in @shared/creator-links so forks can customize one file. The home page, auth screens, and dashboards render CreatorAttribution, which appends UTM params (utm_source=dev-starter&utm_medium=referral&utm_campaign=starter-clone) to portfolio and GitHub URLs for referral tracking.
Update packages/shared/src/creator-links/index.ts when you fork this starter for your own project.
| Command | Purpose |
|---|---|
pnpm dev:procs |
Start DB + app + Prisma Studio via mprocs |
pnpm dev |
Next.js dev server only |
pnpm build |
Production build |
pnpm start |
Run production build locally |
pnpm docker:dev |
Start local PostgreSQL |
pnpm db:migrate |
Apply dev migrations |
pnpm db:seed |
Seed admin account |
pnpm db:studio |
Open Prisma Studio |
pnpm secrets:decrypt |
Decrypt secrets/local.enc.yaml → .env |
pnpm type-check |
TypeScript across app + packages |
pnpm test:unit |
Vitest unit tests |
pnpm lint |
ESLint |
pnpm format:check |
Prettier check |
Full quality gate:
pnpm format:check && pnpm lint && pnpm db:check-migration && pnpm type-check && pnpm test:unit && pnpm build- Runtime contracts: infrastructure/
- Deploy workflow: .github/workflows/root-deploy-production.yml
- Health check:
GET /api/health - Encrypted production env:
secrets/production.enc.yaml→.env.production
Details: Production runtime.
| Doc | Topic |
|---|---|
| docs/architecture/codebase-structure.md | Folder layout and policies |
| docs/setup/local-development.md | Local dev, auth, database |
| docs/setup/secrets/sops-secret-management.md | age + SOPS setup |
| docs/deployment/github-governance.md | Branches, commits, PRs, CI |
| docs/testing/quality-gates.md | Pre-ship checks |
| AGENTS.md | Repo rules for humans and coding agents |
Each major folder also has an AGENTS.md with boundary rules.
- Read AGENTS.md before editing.
- One Next.js app with a production deploy path on
main. - Never commit
.env,.age-key.txt, or generated Prisma client output. - Use Conventional Commits; see GitHub governance.
- Coding agents should not commit, push, or open PRs without explicit approval.
- Next.js 16, React 19, TypeScript 5
- Tailwind CSS 4, Prisma 7, PostgreSQL
- bcryptjs + jose (password hashing, session JWT)
- Vitest, ESLint, Prettier, Husky
- pnpm workspaces (
database,shared)