ProjectTemplates · 2026
Next.js Production Template
A Next.js 16 starter with typed configuration, testing, linting, Docker and CI/CD, so a new project begins past the setup.
- Next.js 16
- TypeScript
- Tailwind CSS
- Vitest
- Docker
pnpm install pnpm devNext.js 16 (Turbopack)- Local: http://localhost:3000Ready in 1.2s pnpm test && pnpm lint✓ __tests__/utils/string.test.ts (8 tests)✓ no ESLint warnings or errorsTemplates · Project
This is the Next.js starter I clone when I begin something new. Next.js 16 with the App Router, React 19, strict TypeScript, Tailwind CSS 4 and pnpm, with the tooling and the deployment story already wired up. It exists so the first commit of a project can be a feature instead of setup.
The work a new application needs is not the interesting work, and it is exactly what gets postponed. Typed environment variables, error boundaries, a Docker image that is not the naive one, a CI job that runs what I run locally. Postponed to release week, all of it lands at once.
Wired before the features
Environment variables are typed in env.ts with @t3-oss/env-nextjs and Zod, split into server and client blocks over an explicit runtimeEnv map. A missing key fails the build rather than a request in production. Vitest runs the unit tests through jsdom and Testing Library. Prettier carries plugins for import sorting, Tailwind class order, JSDoc and JSON key order, and Husky with lint-staged runs it on commit. The GitHub Actions workflow splits into four jobs: lint and format, tests with coverage, build, and tsc --noEmit. The Dockerfile is multi-stage on Node 22 Alpine. It installs through corepack pnpm with a cache mount and ships standalone output under a non-root nextjs user.
Examples, hooks and skills
hooks/ holds twenty small hooks covering storage, fetching, media queries, click outside, debounce, throttle, intervals and intersection. utils/ covers dates and timezones, durations, strings and numbers, files, URLs, caching and Zod validation, plus a small MDX reader. docs/ explains bundle optimization, runtime selection, naming conventions and the Docker build. The UI components under components/examples/ui are labelled reference only, and the README says to build your own. The repository also vendors agent skills under .agents/skills, covering Next.js conventions, React performance rules and composition patterns, mirrored into .claude, .cursor and .agent so any harness finds them.
Choices and their cost
- Examples instead of a component library. A design system that arrives with a template is a design system nobody chose. The cost is that a new project starts with no buttons, and
components/examples/uineeds its own README explaining that it is not the answer. - Validation at build time rather than at request time. A missing key becomes a failed deploy instead of a 500 at midnight. The cost is a
SKIP_ENV_VALIDATIONescape hatch, which CI itself sets for both the test job and the build job. - Four CI jobs rather than one. A failure names itself, and a lint error cannot hide a type error. Each job reinstalls dependencies, so the wall clock time is longer than a single job would be.
- Everything sits on a current major: Next 16, React 19, Tailwind 4, ESLint 10, Zod 4. Starting current beats migrating later. The cost is that a template on the newest majors goes stale quickly, and I would rather automate that refresh than keep doing it by hand.
Cloning and running
pnpm install
pnpm dev
pnpm test && pnpm lint && pnpm typecheck
pnpm build && pnpm analyze
docker build -t app . && docker run -p 3000:3000 app
Both pnpm dev and pnpm build run Turbopack. pnpm analyze sets ANALYZE=true and rebuilds so the bundle analyzer can report what the bundle became. The Docker image builds from the same source and runs node server.js from the standalone output on port 3000. That is the artefact a deploy target actually receives, so it is worth building once before the first deploy rather than during it.
Rough edges and status
The CI workflow triggers on a branch named none, so nothing runs until a project points it at real branches. Coverage upload expects a CODECOV_TOKEN secret that a fresh clone does not have. The typed env file is a scaffold with two variables in it, NODE_ENV and an optional NEXT_PUBLIC_APP_URL, so a real application extends it on day one. There are three test files, which is enough to prove the runner works and not enough to cover anything. It is open source under MIT, and I treat it as a starting point I re-cut rather than a product with releases.
Next projectAgentic AI