Next.js (App Router) Developer
Build production-ready Next.js web features using the App Router with Server Components, server actions, Suspense streaming, and Tailwind CSS. All features consume the shared Rails API backend.
the std-nextjs skill
Development Workflow
Step 1: Understand the Feature
- Clarify the page structure and URL hierarchy.
- Determine which parts need server rendering (SEO, initial data) vs client interactivity.
- Identify data sources — Rails API endpoints, ISR revalidation strategy.
- Determine if server actions are needed for mutations.
- Check if middleware is required (auth, locale, redirects).
Step 2: Define Domain Types
Same as ReactJS SPA — create in next/src/domain/ or next/src/types/:
// next/src/domain/order.ts — Pure TypeScript, no framework imports
export interface Order { id: string; status: OrderStatus; totalAmount: number; }
export type OrderStatus = 'pending' | 'confirmed' | 'shipped' | 'delivered' | 'cancelled';
Step 3: Build Server Component Pages
// next/app/orders/page.tsx
import type { Metadata } from 'next';
import { OrderTable } from '@/components/OrderTable';
import { railsApi } from '@/api/client';
export const metadata: Metadata = {
title: 'Orders | MyApp',
description: 'View and manage your orders',
};
export const revalidate = 60; // ISR: revalidate every 60 seconds
export default async function OrdersPage() {
const orders = await railsApi.get('/api/v1/orders');
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">Orders</h1>
<OrderTable initialData={orders} />
</div>
);
}
Step 4: Build Server Actions
Create server actions in next/src/actions/ for mutations:
// next/src/actions/orders.ts
'use server';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';
const CreateOrderSchema = z.object({ /* ... */ });
export async function createOrder(prevState: unknown, formData: FormData) {
const parsed = CreateOrderSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) return { errors: parsed.error.flatten().fieldErrors };
// Call Rails API, then revalidate
revalidatePath('/orders');
return { success: true };
}
Step 5: Add Loading and Error Boundaries
// next/app/orders/loading.tsx
export default function OrdersLoading() {
return <OrderTableSkeleton />;
}
// next/app/orders/error.tsx
'use client';
export default function OrdersError({ error, reset }: { error: Error; reset: () => void }) {
return (
<div className="text-center">
<p className="text-red-600">Failed to load orders</p>
<button className="mt-2 text-blue-600 underline">Try again</button>
</div>
);
}
Step 6: Add Client Components (When Needed)
Extract interactive parts into separate Client Components:
// next/src/components/OrderFilters.tsx
'use client';
import { useRouter, useSearchParams } from 'next/navigation';
export function OrderFilters() {
const router = useRouter();
const searchParams = useSearchParams();
// Client-side filtering with URL state
}
Step 7: Configure Metadata and SEO
- Every page exports
metadataorgenerateMetadata. - Dynamic pages use
generateMetadatawith data fetching. - Add Open Graph and Twitter card metadata for social sharing.
- Set canonical URLs to prevent duplicate content.
Step 8: Add Middleware (If Needed)
// next/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth_token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
}
Step 9: Testing
- Server Components: Test as async functions — call and assert on returned JSX.
- Server Actions: Test as async functions with FormData input.
- Client Components: Test with React Testing Library (same as ReactJS SPA).
- MSW for mocking Rails API responses.
Step 10: Deployment
Vercel
# Install CLI
npm i -g vercel
# Deploy preview
vercel
# Deploy production
vercel --prod
AWS ECS (standalone)
# Set standalone output in next.config.ts
# Build and deploy as Docker container
next build
docker build -t myapp-next .
Checklist Before Done
- Server Components used for data fetching (no
'use client'on pages) - Every page exports
metadataorgenerateMetadata -
loading.tsxanderror.tsxboundaries in place - Server actions validate input with zod
- Server actions call
revalidatePath/revalidateTagafter mutations -
next/imagefor images,next/linkfor navigation - Responsive Tailwind CSS design
- Accessibility: semantic HTML, keyboard navigation, WCAG AA contrast
- Tests for server components, server actions, and client components
Deep guides (read on demand, do not preload)
- Server Component pages,
generateMetadata, server actions with validation + revalidation, Route Handlers (BFF) →references/server-patterns.md - Progressive-enhancement forms, Client Components with TanStack Query →
references/client-patterns.md - Root layout providers, loading/error boundaries, auth+locale middleware, Server Component and server-action tests →
references/infrastructure-patterns.md
Owned by std-nextjs (scoped to App Router work)
This targets Next.js 15+. That is not a footnote: 15 changed caching defaults and request
APIs, so the same code behaves differently on 14 — fetch is not cached by default,
GET route handlers are not cached, and cookies()/params are async
(await params, await cookies()). Guidance that does not say which major it means is guidance
you cannot check. The version table and both consequences live in the std-nextjs skill body.
- Choosing the Server/Client boundary →
@skills/std-nextjs/references/rendering.md - Server actions: writing mutations →
@skills/std-nextjs/references/server-actions.md - Caching, ISR, revalidation →
@skills/std-nextjs/references/caching.md - Middleware, SEO metadata, deployment →
@skills/std-nextjs/references/middleware-seo-deploy.md