A Next.js 16 template with modern tooling and CI/CD automation. Code quality checks (linting, formatting, type checking, testing) run via Lefthook locally and GitHub Actions on PRs. Dependency updates automated via Dependabot. Deployments handled by Vercel: Preview for PRs, Production for main. Assumes Claude Code.
-
Follow xdocs/project-setup.md to clone, set up GitHub, set up Vercel.
-
Install UI components like shadcn/ui
-
Replace page.tsx, layout.tsx, counter.tsx, button.tsx, theme-toggle.tsx (use an icon), globals.css, fonts.ts
For exact list see package.json
| Category | Tool | What it does |
|---|---|---|
| Language | TypeScript 5 | Static type checking with strict mode enabled |
| Styling | Tailwind CSS v4 | Utility-first CSS framework for rapid styling |
| next-themes | Light/dark mode theming provider | |
| Linting | Biome | Fast linter and formatter (replaces ESLint + Prettier) |
| markdownlint-cli2 | Lints markdown files for consistent formatting | |
| Testing | Vitest | Fast unit test runner (Vite-native, Jest-compatible) |
| Playwright | E2E browser testing (Chromium, Firefox, WebKit, Mobile) | |
| Testing Library | React component testing utilities | |
| Git Hooks | Lefthook | Runs checks on commit/push (lint, typecheck, tests) |
| Optimisation | React Compiler | Automatic memoisation and performance optimisations |
| Analytics | Vercel Speed Insights | Real user performance metrics viewable on Vercel |
| Vercel Web Analytics | Privacy-friendly visitor analytics viewable on Vercel |
This template was initialised with the following options and then updated:
# 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 customise the import alias (@/* by default)? β No
# Update all dependencies to latest versions
npm outdated # Check outdated packages (2025-11-20)
npx npm-check-updates -u # Rewrite package.json with latest
npm install # Install updated versions| File | What | Generally In This Project Template |
|---|---|---|
| β’ .gitattributes | Git line ending and file type handling | Normalises line endings across platforms for consistent Git diffs |
| β’ .gitignore | Files and directories Git should ignore | Prevents build outputs and dependencies from being committed |
| β’ .markdownlint.yaml | Markdownlint configuration | Disables strict linting rules for practical writing |
| β’ .vscode/extensions.json | VS Code extension recommendations | Useful extensions to use in this Next.js project |
| β’ .vscode/settings.json | VS Code editor and formatting settings | Enables auto-formatting and configures Biome and Tailwind extensions |
| πΊ .claude/commands/ | Claude Code repeatable prompts | Write commits, evaluate CodeRabbit comments etc. |
| πΊ .claude/settings.json | Claude Code permissions | Allow/Deny permissions for files, commands, websearch etc |
| πΊ .mcp.json | Claude Code MCP config | e.g. Playwright MCP so Claude Code can "see" app and adjust |
| πΊ CLAUDE.md | Claude Code project context | Documents tech stack for Claude Code (customise!) |
| π ½ next.config.ts | Next.js framework configuration | Enables React Compiler and customises Next.js build settings |
| π ½ package.json | Project dependencies and npm scripts | Defines project dependencies, scripts, and npm package metadata |
| π ½ postcss.config.mjs | PostCSS plugins config for CSS processing | Enables Tailwind CSS v4 processing via PostCSS plugin |
| π§ͺ biome.json | Biome linter and formatter | Sets linting rules, formatting style, and import organisation |
| π§ͺ lefthook.yml | Git hooks manager | Automates code quality checks on commit and E2E tests on push |
| π§ͺ tsconfig.json | TypeScript compiler settings | Configures TypeScript compiler options and module resolution behaviour |
| π§ͺ playwright.config.ts | Playwright E2E test runner configuration | Sets test browsers (desktop + mobile), parallel execution, and base URLs |
| π§ͺ .playwright/ | Playwright test outputs (custom organisation) | Contains test artifacts in test-results/ and HTML playwright-report/ (all Playwright outputs nested under /.playwright/ for clean structure) |
| π§ͺ vitest.config.ts | Vitest test runner config | Sets up React component testing environment and references vitest.setup.ts |
| π§ͺ vitest.setup.ts | Global test setup | Adds helpful test assertions like expect(element).toBeVisible() |
| π .github/dependabot.yml | Dependabot config | Automated dependency update PRs weekly (npm + GitHub Actions) |
| π .github/workflows/check-lint-type.yml | GitHub Actions CI workflow | Runs Biome linting/formatting checks and TypeScript type checking on PRs |
| π .github/workflows/test-e2e.yml | GitHub Actions CI workflow | Runs Playwright E2E tests on PRs (builds production, tests browsers, uploads reports) |
| π .github/workflows/test-e2e-vercel.yml | GitHub Actions CI workflow | Runs Playwright E2E tests against Vercel Preview deployments (triggered by Vercel) |
| π .github/workflows/test-unit.yml | GitHub Actions CI workflow | Runs Vitest unit tests on PRs (uses jsdom environment, React Testing Library) |
This diagram shows how CI automation integrates into a typical development workflow:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π» 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 (3s)
β ββ π¨ 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
git push origin feature/add-dark-mode β‘ pre-PUSH hook runs
ββ π Playwright E2E tests β
Pass (then pushed to GH)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β βοΈ GITHUB: Workflows kickoff 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 LTS
β ββ Install dependencies (npm ci)
β ββ Run Biome checks β
Pass
β ββ Run TypeScript checks β
Pass
β
ββ π€ Workflow 2: Unit Tests (vitest)
β ββ Checkout code
β ββ Setup Node.js LTS
β ββ Install dependencies (npm ci)
β ββ Run Vitest tests β
Pass
β
ββ π€ Workflow 3: E2E Tests (playwright)
ββ Checkout code
ββ Setup Node.js LTS
ββ Install dependencies (npm ci)
ββ Install Playwright browsers
ββ Build Next.js production
ββ Run Playwright tests β
Pass
ββ Meanwhile, Vercel deploys Preview ββββββββββββββββββββββββββ
π Vercel: Preview deployment ready
ββ Sends repository_dispatch event to GitHub
ββ π€ Workflow 4: E2E Tests on Vercel Preview
ββ Triggered by Vercel (not PR event)
ββ Runs Playwright against live Preview URL
ββ Tests real Vercel deployment β
Pass
GITHUB PR Status: β
All checks passed
π° CodeRabbit AI Review Complete
ββ 3 nitpick comments posted:
ββ "Consider using const instead of let" (Button.tsx:12)
ββ "Add JSDoc comment" (ThemeContext.tsx:8)
ββ "Extract magic string to constant" (utils.ts:45)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π» Back to Laptop (Addressing 1 out of 3 nitpick comments on open PR)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ Commit 4: Use const instead of let β‘ pre-commit hook runs
git push origin feature/add-dark-mode β‘ pre-push hook runs
ββ π Playwright E2E tests β
Pass (then pushed to GH)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β βοΈ GITHUB (Workflows kick off again on any PR changes)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
New commits pushed β GitHub Actions re-run automatically
β
ββ π€ Lint & Type β
Pass
ββ π€ Unit Tests β
Pass
ββ π€ E2E Tests β
Pass
PR Status: β
All checks passed (1 new commit)
π° CodeRabbit: "Looks good! 1 issue resolved."
Okay I'm ready! [Merge Pull Request] β Click! π
βββββββββββββββββββββββββββββββββββββββββββββββ
β Branch Protection Verified: β
β β
All status checks passed β
β β
Branch is up to date with main β
βββββββββββββββββββββββββββββββββββββββββββββββ
main branch updated (merge commit preserves 4 commits)
ββ π Vercel deployment triggered β Production
Key CI Takeaways
- Local Hooks β Catch issues before commit or reaching GitHub
- GitHub Actions β Validate every PR with fresh environment (reproducible CI)
- Branch Protection β Prevents merging broken code (all checks must pass)
- Fast Feedback β Pre-commit catches 90% of issues locally in ~3s vs ~2min CI wait
- Quality Gates β Code is validated 2Γ (local + CI) before reaching production
(1) Use Ngrok to Test App From Phone
1. Sign up and follow https://dashboard.ngrok.com/get-started/setup/linux
2. Then: (Terminal 1: `npm run dev`) + (Terminal 2: `ngrok http 3000`)
3. Ngrok gives a URL to connect from phone (shareable)(2) How Vitest Pieces Work Together
1. When you run npm test, Vitest loads vitest.config.ts
2. The config tells Vitest to use jsdom and load `vitest.setup.ts`
3. Your test files can use global test functions and extended matchers
4. The @/* import alias works in tests thanks to `vite-tsconfig-paths`
5. React components are compiled with React Compiler (matching prod)(3) GitHub - Protect branch and check GitHub Workflows (i.e. jobs!) passed before allowing to merge the PR
# Go Do This In GitHub on Repo
Create GitHub Branch Ruleset:
- name: "Protect main branch"
- enforced status: Active
- target branch: include default branch (main)
- Rules:
- Restrict deletions
- Require a pull request before merging
- Allowed merge methods: Merge (only)
- Require status checks to pass π₯
- Require branches to be up to date before merging
- Status Checks that are required
- Search to add "Run Lint & Type Checks" job
- Search to add "Run Unit Tests" job
- Search to add "Run E2E Tests" job
- Block force pushes(4) Vercel For Deploys
1. Sign in β New Project β connect to this repo β deploy it
2. Check Vercel Speed Insights and Web Analytics are enabled (see `layout.tsx`)
3. [Optional] GitHub β Branch ruleset β Add "Vercel" status check
- This requires Vercel deployment to succeed before merge (separate from E2E tests)
4. E2E tests on Vercel Preview deployments:
- Vercel auto-triggers `test-e2e-vercel.yml` via repository_dispatch on each Preview deploy
- To bypass Deployment Protection, create the bypass secret:
- Vercel β Project Settings β Deployment Protection β Protection Bypass for Automation β Add Secret
- GitHub β Repository Settings β Secrets β Actions β New repository secret:
Name: VERCEL_AUTOMATION_BYPASS_SECRET
Value: (the secret from Vercel)


