nextjs-code-implementer

Next.js Code Implementation

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "nextjs-code-implementer" with this command: npx skills add masanao-ohba/claude-manifests/masanao-ohba-claude-manifests-nextjs-code-implementer

Next.js Code Implementation

App Router Fundamentals

File Structure

File-based routing with app directory:

app/ ├── layout.tsx # Root layout (required) ├── page.tsx # Home page (/) ├── loading.tsx # Loading UI ├── error.tsx # Error boundary ├── not-found.tsx # 404 page ├── about/ │ └── page.tsx # /about route ├── blog/ │ ├── page.tsx # /blog route │ └── [slug]/ │ └── page.tsx # /blog/[slug] dynamic route └── api/ └── users/ └── route.ts # API route handler

Special Files

File Purpose

layout Shared UI for route segment and its children

page Unique UI for a route

loading Loading UI with Suspense

error Error boundary for route segment

not-found 404 UI for route segment

route API endpoint handler

Page Implementation

Server Component Page

Default - fetches data on server:

// app/blog/page.tsx import { BlogList } from '@/components/blog/BlogList';

interface BlogPageProps { searchParams: { page?: string }; }

export default async function BlogPage({ searchParams }: BlogPageProps) { const page = Number(searchParams.page) || 1; const posts = await fetchBlogPosts(page);

return ( <div> <h1>Blog</h1> <BlogList posts={posts} /> </div> ); }

// Generate static params for static generation export async function generateStaticParams() { return [{ page: '1' }, { page: '2' }]; }

// Generate metadata export async function generateMetadata(): Promise<Metadata> { return { title: 'Blog - My Site', description: 'Latest blog posts', }; }

Client Component Page

Use when interactivity needed at root:

'use client';

import { useState } from 'react'; import { useSearchParams } from 'next/navigation';

export default function InteractivePage() { const [filter, setFilter] = useState('all'); const searchParams = useSearchParams();

return ( <div> <FilterControls value={filter} onChange={setFilter} /> <ContentList filter={filter} /> </div> ); }

Dynamic Routes

// app/blog/[slug]/page.tsx interface PageProps { params: { slug: string }; }

export default async function BlogPost({ params }: PageProps) { const post = await fetchPost(params.slug);

if (!post) { notFound(); // Shows not-found.tsx }

return <article>{/* render post */}</article>; }

// Generate static paths export async function generateStaticParams() { const posts = await fetchAllPosts(); return posts.map((post) => ({ slug: post.slug })); }

Layout Implementation

Root Layout

Required at app root - wraps all pages:

// app/layout.tsx import { Inter } from 'next/font/google'; import { Providers } from './providers'; import './globals.css';

const inter = Inter({ subsets: ['latin'] });

export const metadata = { title: 'My App', description: 'App description', };

export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}> <Providers> <Header /> <main>{children}</main> <Footer /> </Providers> </body> </html> ); }

Nested Layout

// app/dashboard/layout.tsx export default function DashboardLayout({ children, }: { children: React.ReactNode; }) { return ( <div className="dashboard"> <Sidebar /> <main>{children}</main> </div> ); }

Data Fetching

Server Components

Direct async/await in component:

async function UserProfile({ userId }: { userId: string }) { // Fetch happens on server const user = await db.user.findUnique({ where: { id: userId } });

return <div>{user.name}</div>; }

Parallel Fetching:

async function Page() { const [users, posts] = await Promise.all([ fetchUsers(), fetchPosts(), ]);

return <Dashboard users={users} posts={posts} />; }

Sequential Fetching:

async function Page({ params }: { params: { id: string } }) { const user = await fetchUser(params.id); const posts = await fetchUserPosts(user.id);

return <UserProfile user={user} posts={posts} />; }

Client Components

Use React Query for client-side fetching:

'use client';

import { useQuery } from '@tanstack/react-query';

export function UserList() { const { data, isLoading, error } = useQuery({ queryKey: ['users'], queryFn: async () => { const res = await fetch('/api/users'); if (!res.ok) throw new Error('Failed to fetch'); return res.json(); }, });

if (isLoading) return <LoadingSkeleton />; if (error) return <ErrorMessage error={error} />;

return <ul>{data.map(user => <UserItem key={user.id} user={user} />)}</ul>; }

Caching Strategies

Strategy Usage

fetch(url, { cache: 'force-cache' })

Cache forever (default)

fetch(url, { cache: 'no-store' })

Never cache, always fresh

fetch(url, { next: { revalidate: 3600 } })

Cache for 3600s

Loading States

Loading File

Automatic loading UI with Suspense:

// app/dashboard/loading.tsx export default function Loading() { return ( <div className="animate-pulse"> <div className="h-8 bg-gray-200 rounded w-1/4 mb-4" /> <div className="h-64 bg-gray-200 rounded" /> </div> ); }

Suspense Boundaries

Granular loading states:

import { Suspense } from 'react';

export default function Page() { return ( <div> <h1>Dashboard</h1> <Suspense fallback={<StatsSkeleton />}> <Statistics /> </Suspense> <Suspense fallback={<ChartSkeleton />}> <Chart /> </Suspense> </div> ); }

Error Handling

Error File

Error boundary for route segment:

'use client'; // Error components must be Client Components

export default function Error({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return ( <div> <h2>Something went wrong!</h2> <p>{error.message}</p> <button onClick={reset}>Try again</button> </div> ); }

Not Found

// app/blog/[slug]/not-found.tsx export default function NotFound() { return ( <div> <h2>Post Not Found</h2> <p>Could not find the requested blog post.</p> </div> ); }

API Routes

Route Handlers

// app/api/users/route.ts import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const page = searchParams.get('page') || '1';

const users = await db.user.findMany({ skip: (Number(page) - 1) * 10, take: 10, });

return NextResponse.json(users); }

export async function POST(request: NextRequest) { const body = await request.json();

const user = await db.user.create({ data: body, });

return NextResponse.json(user, { status: 201 }); }

Dynamic Routes

// app/api/users/[id]/route.ts export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { const user = await db.user.findUnique({ where: { id: params.id }, });

if (!user) { return NextResponse.json( { error: 'User not found' }, { status: 404 } ); }

return NextResponse.json(user); }

Server Actions

Server-side mutations:

'use server';

import { revalidatePath } from 'next/cache';

export async function createPost(formData: FormData) { const title = formData.get('title') as string; const content = formData.get('content') as string;

const post = await db.post.create({ data: { title, content }, });

revalidatePath('/blog'); return { success: true, post }; }

Usage in Form:

// app/blog/new/page.tsx import { createPost } from '@/app/actions';

export default function NewPost() { return ( <form action={createPost}> <input name="title" required /> <textarea name="content" required /> <button type="submit">Create Post</button> </form> ); }

Metadata

Static Metadata

import { Metadata } from 'next';

export const metadata: Metadata = { title: 'My Page', description: 'Page description', openGraph: { title: 'My Page', description: 'Page description', images: ['/og-image.jpg'], }, };

Dynamic Metadata

export async function generateMetadata({ params, }: { params: { slug: string }; }): Promise<Metadata> { const post = await fetchPost(params.slug);

return { title: post.title, description: post.excerpt, openGraph: { title: post.title, description: post.excerpt, images: [post.coverImage], }, }; }

Image Optimization

import Image from 'next/image';

<Image src="/profile.jpg" alt="Profile picture" width={500} height={500} priority // Load immediately for LCP />

// Remote images <Image src="https://example.com/image.jpg" alt="Remote image" width={800} height={600} // Configure remote patterns in next.config.js />

Middleware

// middleware.ts (at project root) import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) { // Authentication check const token = request.cookies.get('token');

if (!token && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); }

return NextResponse.next(); }

export const config = { matcher: '/dashboard/:path*', };

Internationalization

next-intl Setup

// app/[locale]/layout.tsx import { NextIntlClientProvider } from 'next-intl'; import { getMessages } from 'next-intl/server';

export default async function LocaleLayout({ children, params: { locale }, }: { children: React.ReactNode; params: { locale: string }; }) { const messages = await getMessages();

return ( <NextIntlClientProvider locale={locale} messages={messages}> {children} </NextIntlClientProvider> ); }

Usage

'use client';

import { useTranslations } from 'next-intl';

export function Welcome() { const t = useTranslations('HomePage');

return <h1>{t('title')}</h1>; }

Best Practices Checklist

  • Use Server Components by default

  • Add 'use client' only when necessary

  • Implement loading.tsx for loading states

  • Implement error.tsx for error handling

  • Use generateMetadata for SEO

  • Optimize images with next/image

  • Use server actions for mutations

  • Implement proper caching strategies

  • Handle not-found cases

  • Use TypeScript for type safety

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

react-code-reviewer

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-implementer

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-reviewer

No summary provided by upstream source.

Repository SourceNeeds Review