bundles/frontend/skills/nextjs-validator/SKILL.md
Validate Next.js 16 configuration and detect/prevent deprecated patterns. Ensures proxy.ts usage, Turbopack, Cache Components, and App Router best practices. Use before any Next.js work or when auditing existing projects.
npx skillsauth add shipshitdev/library nextjs-validatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Validates Next.js 16 configuration and prevents deprecated patterns. AI assistants often generate Next.js 14/15 patterns - this skill enforces Next.js 16.
python3 scripts/validate.py --root .
python3 scripts/validate.py --root . --strict
// GOOD: v16+
"next": "^16.0.0"
// BAD: v15 or earlier
"next": "^15.0.0"
GOOD - Next.js 16:
// proxy.ts (Node.js runtime - REQUIRED)
import { createProxy } from 'next/proxy';
export const proxy = createProxy();
BAD - Deprecated:
// middleware.ts (Edge runtime - DEPRECATED)
export function middleware() { }
GOOD:
app/
├── layout.tsx # Root layout
├── page.tsx # Home page
├── (routes)/ # Route groups
│ ├── dashboard/
│ │ └── page.tsx
│ └── settings/
│ └── page.tsx
└── api/ # API routes (optional)
BAD - Pages Router (deprecated):
pages/
├── _app.tsx
├── index.tsx
└── api/
use cacheGOOD - Next.js 16:
// app/dashboard/page.tsx
'use cache';
export default async function Dashboard() {
const data = await fetch('/api/data');
return <DashboardView data={data} />;
}
GOOD:
// app/actions.ts
'use server';
export async function createItem(formData: FormData) {
// Server-side logic
}
GOOD - Default in Next.js 16:
// next.config.ts (Turbopack is default, no config needed)
BAD - Disabling Turbopack:
// Don't disable unless absolutely necessary
experimental: {
turbo: false // BAD
}
GOOD - TypeScript config:
// next.config.ts
import type { NextConfig } from 'next';
const config: NextConfig = {
// ...
};
export default config;
BAD - JavaScript config:
// next.config.js - Prefer .ts
module.exports = { }
| Deprecated (v15-) | Replacement (v16+) |
|-------------------|-------------------|
| middleware.ts | proxy.ts |
| getServerSideProps | Server Components + use cache |
| getStaticProps | Server Components + use cache |
| getStaticPaths | generateStaticParams |
| _app.tsx | app/layout.tsx |
| _document.tsx | app/layout.tsx |
| pages/ directory | app/ directory |
| next/router | next/navigation |
| useRouter() (pages) | useRouter() from next/navigation |
'use cache';
// Entire component cached
export default async function CachedPage() {
const data = await fetchData();
return <View data={data} />;
}
// next.config.ts
const config: NextConfig = {
experimental: {
ppr: true,
},
};
AI-assisted debugging with contextual insight:
// Enable in development
// Works with Claude Code and other MCP-compatible tools
app/
├── @modal/
│ └── login/
│ └── page.tsx
├── @sidebar/
│ └── default.tsx
└── layout.tsx
app/
├── feed/
│ └── page.tsx
├── photo/
│ └── [id]/
│ └── page.tsx
└── @modal/
└── (.)photo/
└── [id]/
└── page.tsx
=== Next.js 16 Validation Report ===
Package Version: [email protected] ✓
File Structure:
✓ Using app/ directory (App Router)
✗ Found pages/ directory - migrate to App Router
✓ Found proxy.ts
✗ Found middleware.ts - migrate to proxy.ts
Patterns:
✓ Using Server Components
✗ Found getServerSideProps in 2 files
✓ Using next/navigation
Config:
✓ next.config.ts (TypeScript)
✓ Turbopack enabled (default)
Summary: 2 issues found
- Migrate pages/ to app/ directory
- Replace middleware.ts with proxy.ts
Before (v15):
// middleware.ts
import { NextResponse } from 'next/server';
export function middleware(request) {
// Edge runtime
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*'],
};
After (v16):
// proxy.ts
import { createProxy } from 'next/proxy';
export const proxy = createProxy({
// Node.js runtime
async handle(request) {
// Full Node.js APIs available
return request;
},
matcher: ['/dashboard/:path*'],
});
Before:
// pages/dashboard.tsx
export async function getServerSideProps() {
const data = await fetchData();
return { props: { data } };
}
export default function Dashboard({ data }) {
return <View data={data} />;
}
After:
// app/dashboard/page.tsx
export default async function Dashboard() {
const data = await fetchData();
return <View data={data} />;
}
# .github/workflows/validate.yml
- name: Validate Next.js 16
run: |
python3 scripts/validate.py \
--root . \
--strict \
--ci
tailwind-validator - Validate Tailwind v4 configbiome-validator - Validate Biome 2.3+ configclerk-validator - Validate Clerk auth setupdevelopment
Create an isolated git worktree from the correct base branch and check it out into a clean, gitignored directory. Use when the user asks to make a worktree, spin up a parallel/isolated workspace, work on something without disturbing the current checkout, branch off the current work, or run multiple agents on the same repo at once. Picks the base branch smartly — the current feature branch when you are on one, otherwise the develop integration branch — so worktrees continue your in-progress work by default instead of forking from the wrong place.
development
Verify a release was fully promoted through develop, staging, and master/main, then prune merged local and remote branches and stale git worktrees. Squash-merge aware — uses GitHub PR merge state as the merge oracle, not commit ancestry. Use when the user asks to clean up branches after a deploy, prune worktrees, remove merged branches, tidy up after promoting develop to staging to master, or confirm nothing stale was left behind before pruning.
development
Structured "done coding, now what?" workflow: verify tests pass, detect the repository environment (normal repo vs worktree, named branch vs detached HEAD), present exactly the right merge / PR / keep / discard options, and execute the chosen path including safe worktree cleanup. Use when implementation is complete and the branch needs to be integrated, published, or abandoned.
tools
Capture a client or stakeholder feature request, turn it into a planner-ready PRD epic with scoped sub-issues, check for duplicate work, and place approved issues on a GitHub Projects kanban. Use when a user invokes feature intake, asks to turn a rough client requirement into GitHub issues, or wants an idea written as a PRD and pushed to a board.