# Next.js 16 Template

*A Next.js 16.4 template. Lint, format, type and unit-test checks run on every commit, and end-to-end tests on every push. Every PR repeats these checks on GitHub and adds end-to-end tests against a Vercel Preview. A branch ruleset ([one-time setup](docs/project-setup.md)) blocks merging to `main` until they pass. Merging deploys to Vercel Production, where the end-to-end tests run again. Dependabot opens PRs automatically for security fixes and GitHub Actions updates. Claude Code is set up, plugins included. [You choose the rest](#you-choose-the-rest): UI components, database, etc.*
## ๐ฏ Use This Template
**Prerequisites:** [Claude Code](https://code.claude.com), [Git](https://git-scm.com), [GitHub CLI](https://cli.github.com) (logged in via `gh auth login`) and [Node.js 26](https://nodejs.org) for Next.js. To check and install them, give Claude Code [this README](https://raw.githubusercontent.com/michellepace/nextjs-template/refs/heads/main/README.md) and ask it to install only the missing prerequisites.
(1) Get the Code โ fresh start or keep history
Pick one, swapping `my-app` for your new repository name:
```bash
# Fresh start, no template history (same as the "Use this template" button)
gh repo create my-app --template michellepace/nextjs-template --public --clone
cd my-app
```
```bash
# Keep history: Claude can read the template's commits to answer "why was this done?"
git clone https://github.com/michellepace/nextjs-template.git my-app
cd my-app
git remote remove origin
gh repo create my-app --public --source . --push
git remote set-head origin --auto # record main as default, as a clone does
```
Keep `--public` unless you have GitHub Pro โ free accounts can't protect `main` on private repos.
(2) Install and Run โ dependencies, test browsers, dev server
```bash
npm install # Dependencies + git hooks
npx playwright install chromium webkit --with-deps # Browsers for E2E tests
npm run dev # Open http://localhost:3000 (Ctrl+C to stop)
```
(3) Set Up Claude Code โ global tools and plugins
Install the tools Claude Code's TypeScript plugin and browser skill need:
```bash
# typescript-lsp plugin runs this. It then uses the project's TypeScript
npm install -g typescript-language-server
# Browser automation for Claude. Rerun both lines to upgrade the CLI:
# the second line rewrites .claude/skills/playwright-cli/ to match it
npm install -g @playwright/cli@latest
playwright-cli install --skills
```
Then run `claude` in the project folder, trust it, and accept the offer to install the plugins in [`.claude/settings.json`](.claude/settings.json). If you skipped the offer, run:
```bash
claude plugin marketplace add anthropics/claude-plugins-official --scope project
claude plugin marketplace add michellepace/my-claude-marketplace --scope project
claude plugin install typescript-lsp@claude-plugins-official --scope project
claude plugin install alwayson-misc@my-claude-marketplace --scope project
claude plugin install git-utils@my-claude-marketplace --scope project
claude plugin install mattpocock-skills@claude-plugins-official --scope project # enable
claude plugin disable mattpocock-skills@claude-plugins-official --scope project # disable again
```
- **mattpocock-skills** is disabled: its many skills fill the context window and trigger when you don't want them. Turn it on with `claude plugin enable mattpocock-skills@claude-plugins-official --scope project`.
- **[git-utils](https://github.com/michellepace/my-claude-marketplace/tree/main/plugins/git-utils)** is my own plugin and optional. Ask Claude to remove or disable it.
(4) Install Extensions โ VS Code / Cursor
In VS Code or Cursor, install the extensions listed in [`.vscode/extensions.json`](.vscode/extensions.json). When the editor asks to use the workspace TypeScript version, click Allow โ this turns on the Next.js editor checks.
Missed it? Open a `.tsx` file, press Ctrl+Shift+P and run **TypeScript: Select TypeScript Version** โ **Use Workspace Version**.
(5) GitHub + Vercel Setup โ deploys, CI, branch protection
Follow [`docs/project-setup.md`](docs/project-setup.md) to set up GitHub and Vercel.
(6) Housekeeping โ make the Claude Code config yours
Modify [`.claude/CLAUDE.md`](.claude/CLAUDE.md), [`.mcp.json`](.mcp.json), and [`.claude/settings.json`](.claude/settings.json) (permissions and plugins) as preferred.
(7) Choose UI Library โ shadcn/ui, HeroUI or Tailwind Plus
Choose one that supports Tailwind 4. [shadcn/ui](https://ui.shadcn.com/) (free) and [HeroUI v3](https://heroui.com/) (free) are both LLM friendly and use semantic tokens โ which makes theming easy. shadcn is ubiquitous so theme it well to stand out โ [tweak-cn](https://tweakcn.com/) and [theme-generator](https://shadcnstudio.com/theme-generator) are helpful. HeroUI is more visually distinct and extremely LLM friendly; it ships with agent skills too. [Tailwind Plus](https://tailwindcss.com/plus) (paid) offers components ([Catalyst](https://tailwindcss.com/plus/ui-kit)), assembled UI blocks, and full site templates, but doesn't include semantic tokens so centralised theming takes more manual work.
(8) Decide on Icons โ each UI library ships its own
Each UI library above ships with icons โ shadcn/ui uses [Lucide React](https://lucide.dev/guide/react/), Tailwind Plus (Catalyst) uses [Heroicons](https://heroicons.com/), HeroUI uses [Iconify](https://iconify.design/). All three let you swap to a different icon library.
(9) Replace Template Files โ your pages, theme and fonts
Replace [`app/page.tsx`](app/page.tsx), [`app/layout.tsx`](app/layout.tsx), [`components/button.tsx`](components/button.tsx), [`app/globals.css`](app/globals.css) (centralised theming), [`app/fonts.ts`](app/fonts.ts), and [`components/theme-toggle.tsx`](components/theme-toggle.tsx) (use an icon).
## What's Installed?
For exact list see [`package.json`](package.json)
| Category | Tool | What it does |
| :------- | :--- | :----------- |
| Runtime | [Node.js 26 LTS](https://nodejs.org) | Major version set in [`.nvmrc`](.nvmrc), and in `engines` and `@types/node` in [`package.json`](package.json); raise all three together |
| Framework | [Next.js 16.4](https://nextjs.org) | Core webapp foundation โ routing, rendering, API routes, optimisation, and builds |
| Language | [TypeScript 6](https://www.typescriptlang.org) | Static type checking with strict mode enabled โ not 7 yet, which can't run the Next.js editor plugin |
| Styling | [Tailwind CSS v4](https://tailwindcss.com) | Utility-first CSS framework for rapid styling |
| | [next-themes](https://github.com/pacocoursey/next-themes) | Light/dark mode theming provider |
| Linting | [Biome](https://biomejs.dev) | Fast linter and formatter (replaces ESLint + Prettier) |
| | [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) | Lints markdown files for consistent formatting |
| Testing | [Vitest](https://vitest.dev) | Fast unit test runner (Vite-native, Jest-compatible) |
| | [Playwright](https://playwright.dev) | E2E browser testing (Chromium, Mobile Safari) |
| | [Testing Library](https://testing-library.com) | React component testing utilities |
| Git Hooks | [Lefthook](https://lefthook.dev) | Runs checks on commit (lint, typecheck, unit tests) and push (build, E2E tests) |
| Optimisation | [React Compiler](https://react.dev/learn/react-compiler) | Automatic memoisation and performance optimisations |
| Analytics | [Vercel Speed Insights](https://vercel.com/docs/speed-insights) | Real user performance metrics viewable on Vercel |
| | [Vercel Web Analytics](https://vercel.com/docs/analytics) | Privacy-friendly visitor analytics viewable on Vercel |
## You Choose the Rest
You'll need:
- UI components (e.g. shadcn/ui, HeroUI v3, Tailwind Plus)
- Database/ORM (e.g. Neon or Supabase with Prisma or Drizzle. Or Convex - no ORM needed!)
- Authentication (e.g. Clerk, Supabase Auth, or Better Auth โ open source, Vercel-owned)
- Validation (e.g. Zod, to check form and API data on the server)
Maybe:
- Forms (e.g. React Hook Form, for complex forms)
- State management (e.g. Zustand, Jotai, or React Context)
## This Repo Explained
Next.js Installation โ the create-next-app answers
This template was initialised with the following options:
```bash
# Next.js installer
$ npx create-next-app@latest
Would you like to use TypeScript? โ๏ธ Yes
Which linter would you like to use? โ๏ธ Biome
Would you like to use React Compiler? โ๏ธ Yes
Would you like to use Tailwind CSS? โ๏ธ Yes
Would you like your code inside a src/ directory? โ No
Would you like to use App Router? (recommended) โ๏ธ Yes
Would you like to use Cache Components? โ๏ธ Yes
Would you like to customise the import alias (@/* by default)? โ No
Would you like to include AGENTS.md to guide coding agents? โ๏ธ Yes
Would you like to help improve Next.js by letting agents prepare anonymised feedback? โ No
```
Config Files โ what each one does
*Key: ๐บ Claude Code ยท ๐
ฝ Next.js ยท ๐งช Checks and tests ยท ๐ GitHub CI/CD*
| File | What it does |
| :----- | :----- |
| ๐บ [`.claude/rules/`](.claude/rules/) | Claude Code rules, loaded only when Claude works with matching file paths |
| ๐บ [`.claude/CLAUDE.md`](.claude/CLAUDE.md) | Claude Code project instructions: tech stack, conventions, traps and commands (customise!) |
| ๐บ [`.claude/settings.json`](.claude/settings.json) | Claude Code project settings: allow/deny permissions, enabled plugins and marketplaces |
| ๐ [`.github/workflows/check-lint-type.yml`](.github/workflows/check-lint-type.yml) | CI workflow: runs Biome and TypeScript checks on every PR; must pass to merge |
| ๐ [`.github/workflows/test-e2e-vercel.yml`](.github/workflows/test-e2e-vercel.yml) | CI workflow: runs Playwright E2E tests against each live Vercel deploy, to catch what only breaks on Vercel; Preview must pass to merge, Production is checked after merge (can't block) |
| ๐ [`.github/workflows/test-e2e.yml`](.github/workflows/test-e2e.yml) | CI workflow: builds for production and runs Playwright E2E tests on every PR; must pass to merge |
| ๐ [`.github/workflows/test-unit.yml`](.github/workflows/test-unit.yml) | CI workflow: runs Vitest unit tests on every PR; must pass to merge |
| ๐ [`.github/dependabot.yml`](.github/dependabot.yml) | Dependabot config: weekly PRs to update GitHub Actions |
| ๐งช [`.playwright/`](.playwright/) | Playwright test outputs (`test-results/`, `playwright-report/`), kept here instead of project root, plus `cli.config.json` for playwright-cli |
| ๐บ `.playwright-cli/` | playwright-cli output: page snapshots and screenshots Claude takes when it drives a browser (git-ignored) |
| [`.vscode/extensions.json`](.vscode/extensions.json) | Recommended VS Code extensions, so your editor uses this repo's tools: lint and format, Tailwind autocomplete, etc. |
| [`.vscode/settings.json`](.vscode/settings.json) | VS Code workspace settings: Biome format on save, Tailwind IntelliSense, the project's TypeScript |
| [`.gitattributes`](.gitattributes) | Git line-ending rules, so diffs match across platforms (Windows, macOS, Linux) |
| [`.gitignore`](.gitignore) | Files Git ignores: dependencies, build output, test output, secrets, etc. |
| ๐งช [`.markdownlint-cli2.yaml`](.markdownlint-cli2.yaml) | Markdown linter config: rules to switch off and files to skip when checking markdown files |
| ๐บ [`.mcp.json`](.mcp.json) | Claude Code MCP servers: Ref, for docs search (optional; set API key in `API_KEY_MCP_REF` environment variable) |
| [`.nvmrc`](.nvmrc) | Node.js version pin: CI and `nvm use` read it, so your machine and CI run the same Node major |
| ๐งช [`biome.jsonc`](biome.jsonc) | Biome config: one set of lint and format rules, used by your editor on save, git hooks and CI |
| ๐งช [`lefthook.yml`](lefthook.yml) | Git hooks config: lint, typecheck and unit tests on commit; build and E2E tests on push, so most problems are caught before CI |
| ๐
ฝ [`next.config.ts`](next.config.ts) | Next.js config: React Compiler, Cache Components, partial prefetching, typed routes |
| ๐
ฝ [`package.json`](package.json) | Packages the app uses and the versions each may update to, npm scripts, and the allowed Node versions |
| ๐งช [`playwright.config.ts`](playwright.config.ts) | Playwright E2E test config: browsers to test in, and the site to test (local server or a Vercel deployment) |
| ๐
ฝ [`postcss.config.mjs`](postcss.config.mjs) | PostCSS config: runs Tailwind on your CSS (the theme lives in `app/globals.css`) |
| ๐งช [`tsconfig.json`](tsconfig.json) | TypeScript config: strict type checking, and `@/` imports that start from the project root |
| ๐งช [`vitest.config.ts`](vitest.config.ts) | Vitest unit test config: tests run in a simulated browser (jsdom), with React Compiler on as in the app |
| ๐งช [`vitest.setup.ts`](vitest.setup.ts) | Vitest setup file: runs before each test file; holds shared test setup |
CI/CD Workflow โ from first commit to production
```text
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ป LAPTOP: Create a new branch (tests on local dev machine)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
git checkout -b feature/add-dark-mode
โ
โโ Commit 1: Add light/dark mode โก pre-commit hook runs
โ โโ ๐จ Biome lint and format โ
Auto-fixed & staged
โ โโ ๐ TypeScript type check โ
Pass
โ โโ ๐งช Vitest unit tests โ
Pass
โ (then committed on all pass)
โ
โโ Commit 2: (some more work here) โก pre-commit hook runs again
โ
โโ Commit 3: (some more work here) โก pre-commit hook runs again
(optional) /simplify, /code-review, /security-review before pushing
see docs/project-setup.md ยง Checking Quality
git push origin feature/add-dark-mode โก pre-PUSH hook runs
โโ ๐๏ธ Next.js production build โ
Pass
โโ ๐ญ Playwright E2E tests โ
Pass (then pushed to GH)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ๏ธ GITHUB: Workflows kick off on GitHub machines when PR is created
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Create Pull Request โ GitHub Actions triggered automatically
โ
โโ ๐ค Workflow 1: Lint & Type (biome, tsc)
โ โโ Checkout code
โ โโ Setup Node.js (from .nvmrc)
โ โโ Install dependencies (npm ci)
โ โโ Run Biome checks โ
Pass
โ โโ Run TypeScript checks โ
Pass
โ
โโ ๐ค Workflow 2: Unit Tests (vitest)
โ โโ Checkout code
โ โโ Setup Node.js (from .nvmrc)
โ โโ Install dependencies (npm ci)
โ โโ Run Vitest tests โ
Pass
โ
โโ ๐ค Workflow 3: E2E Tests (playwright)
โโ Checkout code
โโ Setup Node.js (from .nvmrc)
โโ Install dependencies (npm ci)
โโ Install Playwright browsers
โโ Build Next.js production
โโ Run Playwright tests โ
Pass
โโ Meanwhile, Vercel deploys Preview โโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Vercel: Preview deployment ready
โโ โ
Vercel deployment status check (required to merge)
โโ Sends repository_dispatch event to GitHub
โโ ๐ค Workflow 4: E2E Tests (Vercel)
โโ Triggered by Vercel (not PR event)
โโ Runs Playwright against live Preview URL
โโ Tests real Vercel deployment โ
Pass
โโ Reports status back to PR commit
GITHUB PR Status: โ
All checks passed
(push more commits to the PR and every workflow runs again)
Okay I'm ready! [Merge Pull Request] โ Click! ๐
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Ruleset Verified: "Protect main branch" โ
โ โ
All 5 required status checks passed โ
โ โ
Branch is up to date with main โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
main branch updated (merge commit preserves 3 commits)
โโ ๐ Vercel deployment triggered โ Production
โโ ๐ค Workflow 4 again: E2E Tests (Vercel)
โโ Runs Playwright against Production URL โ
Pass
โโ Reports status to merge commit (can't block, already live)
```
Key CI Takeaways
- Local Hooks โ Catch issues before commit or reaching GitHub
- GitHub Actions โ Validate every PR with fresh environment (reproducible CI)
- GitHub Ruleset โ Prevents merging broken code (all checks must pass)
- Fast Feedback โ Pre-commit catches most issues locally
- Quality Gates โ Code is validated 2ร (local + CI) before reaching production