active

TypeScript Next.js Rules

Safe
System VerifiedSafe

Context rules for AI agents working in TypeScript/Next.js App Router projects. Covers strict typing, server vs client components, Tailwind, Zod, and file conventions.

@api/typescript-next-js-rules

typescript
nextjs
react
rules
context
tailwind

TypeScript Next.js Rules

Context skill: Install this into your agent to enforce consistent, production-quality patterns in TypeScript Next.js App Router projects. Works with Claude Code, Cursor, Windsurf, and any agent that reads context files.


Stack Assumptions

  • Next.js 14+ with App Router (not Pages Router)
  • TypeScript with strict mode enabled ("strict": true in tsconfig)
  • Tailwind CSS for styling
  • Zod for runtime validation
  • Supabase or Prisma for database (adapt as needed)

File & Directory Conventions

code
app/
  (group)/          ← Route groups (no URL segment)
    layout.tsx      ← Shared layout
    page.tsx        ← Route page (server component by default)
    loading.tsx     ← Suspense fallback
    error.tsx       ← Error boundary ('use client' required)
  api/
    route.ts        ← API routes (GET, POST, etc. as named exports)
components/
  ui/               ← Primitive UI: Button, Card, Badge, etc.
  feature/          ← Feature-specific composed components
lib/
  utils/            ← Pure utility functions (no React)
  types/            ← TypeScript type definitions
  actions/          ← Server Actions
hooks/              ← Custom React hooks (client-side)

Server vs Client Components

Default to Server Components. Only add 'use client' when you need:

  • useState or useReducer
  • useEffect or lifecycle hooks
  • Browser APIs (window, localStorage, etc.)
  • Event handlers that run in the browser
  • Third-party client-only libraries

Never put 'use client' at the top of a layout file.


TypeScript Rules

typescript
// ✅ Always type function return values explicitly
async function getUser(id: string): Promise<User | null> { ... }

// ✅ Use `type` for unions/intersections, `interface` for object shapes
type Status = 'pending' | 'active' | 'archived'
interface UserProfile { id: string; email: string; }

// ✅ Never use `any` — use `unknown` and narrow
function parse(input: unknown): string {
  if (typeof input !== 'string') throw new Error('Expected string')
  return input
}

// ❌ Never
const data: any = response.json()

// ✅ Type API responses with Zod
const UserSchema = z.object({ id: z.string().uuid(), email: z.string().email() })
type User = z.infer<typeof UserSchema>

API Routes

typescript
// app/api/users/route.ts
import { NextResponse } from 'next/server'
import { z } from 'zod'

const CreateUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
})

export async function POST(request: Request) {
  const body = await request.json()
  const result = CreateUserSchema.safeParse(body)
  if (!result.success) {
    return NextResponse.json({ error: result.error.flatten() }, { status: 422 })
  }
  // ... proceed with result.data (fully typed)
}

Data Fetching

typescript
// ✅ Server Component data fetching — no useEffect
export default async function UsersPage() {
  const users = await getUsers() // Direct async call in component
  return <UserList users={users} />
}

// ✅ Parallel fetching with Promise.all
const [user, posts] = await Promise.all([getUser(id), getPosts(id)])

// ✅ Use `cache` for request deduplication
import { cache } from 'react'
const getUser = cache(async (id: string) => { ... })

Error Handling

typescript
// ✅ Never throw in Server Components — use error.tsx
// app/(main)/error.tsx
'use client'
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
  return <div><h2>Something went wrong</h2><button onClick={reset}>Try again</button></div>
}

// ✅ API routes always return typed error shapes
return NextResponse.json({ error: 'Not found', code: 'USER_NOT_FOUND' }, { status: 404 })

Tailwind CSS

  • Use Tailwind utility classes directly — no custom CSS unless absolutely necessary
  • Use cn() helper (from clsx + tailwind-merge) to conditionally join classes
  • Dark mode via dark: variants (not separate stylesheets)
  • Never use inline style={{}} for values that Tailwind covers
  • Use @apply sparingly — only in component-level .module.css files if needed

Do Not

  • Do not use pages/ directory — App Router only
  • Do not import server-only code into client components (will cause runtime errors)
  • Do not use getServerSideProps or getStaticProps — use async Server Components
  • Do not console.log in production code — use a proper logger
  • Do not hardcode environment variables — use process.env.VAR with validation on startup
  • Do not use default exports for utility functions — named exports only
Dormant$0/mo

$20 more to next tier

Info

Created February 20, 2026
Version 1.0.0
Context
Terminal output

Embed

Add this skill card to any webpage.

<iframe src="https://skillslap.com/skill/8068b095-f3ea-4180-91ce-b3ff7767f61e/embed"
        width="400" height="200"
        style="border:none;border-radius:12px;"
        title="SkillSlap Skill: TypeScript Next.js Rules">
</iframe>