Skip to content
Tutorial··15 min

Build a full-stack Next.js app with Claude Code — complete walkthrough

Real step-by-step: use Claude Code to scaffold, build, and deploy a Next.js 14 App Router app with Supabase auth, a protected dashboard, and a public landing page — in one afternoon.

Build a full-stack Next.js app with Claude Code — complete walkthrough
This is a real walkthrough, not a demo. We're building a working Next.js 14 app — public landing page, GitHub OAuth sign-in, protected dashboard — using Claude Code as the primary coding agent. Every command is real. Every instruction to the agent is exact. What we're building -------------------- - Public landing page (marketing site) - GitHub OAuth sign-in via Supabase Auth - Protected /dashboard route - A simple "saved links" feature (CRUD, stored in Supabase) - Deploy to Vercel Total time: 2-4 hours depending on how much you customise. Claude Code handles probably 80% of the actual typing. Prerequisites -------------- - Node.js 18+, Claude Code installed (npm install -g @anthropic-ai/claude-code) - A Supabase account (free tier works) - A Vercel account (free tier works) - Git + GitHub account Step 1 — Scaffold the project ------------------------------ npx create-next-app@latest my-app --typescript --tailwind --app --eslint cd my-app claude Once Claude Code starts, install the right skill first: claude skills add nextjs-app-router-pro This gives Claude Code pre-loaded context about Next.js 14 patterns — App Router, Server Components, Server Actions, Tailwind. You won't need to explain these every session. Now set up Supabase: > install @supabase/supabase-js and @supabase/ssr. Create lib/supabase/client.ts (browser client) and lib/supabase/server.ts (server client using cookies from next/headers). Use the environment variables NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY. Review what it produces. The server client should use createServerClient from @supabase/ssr with a cookies() adapter. If it uses the older createClient with cookies manually, ask it to update to the ssr pattern. Step 2 — Auth middleware ------------------------- > add a middleware.ts in the project root that uses Supabase to refresh the session on every request. Protect all /dashboard/* routes — redirect unauthenticated users to /sign-in. Public routes: /, /sign-in, /sign-up, /api/auth/callback. Claude Code will write the middleware and update next.config.mjs with the matcher. Read the matcher pattern carefully — a wrong regex here means your /api routes get auth-checked, which breaks everything. Step 3 — Sign-in page ---------------------- > create app/sign-in/page.tsx. It should have a "Sign in with GitHub" button that calls supabase.auth.signInWithOAuth with provider: 'github' and redirectTo pointing to /api/auth/callback. Show a spinner while the redirect is happening. Style it with Tailwind — clean, centered, dark background. Then create the OAuth callback: > create app/api/auth/callback/route.ts. It handles the code exchange for a Supabase session using exchangeCodeForSession, then redirects to /dashboard. Step 4 — Protected dashboard ------------------------------ > create app/dashboard/layout.tsx. It should get the current user from Supabase on the server using the server client. If no user, redirect to /sign-in. Show a simple sidebar with: Dashboard, Saved Links, Settings. Add a sign-out button that calls supabase.auth.signOut via a Server Action and redirects to /. > create app/dashboard/page.tsx. Show "Welcome back, [user.email]" and a count of the user's saved links (query the links table, count only). Step 5 — Saved links feature ------------------------------ First, create the database table. Go to your Supabase dashboard > SQL Editor and run: create table links ( id uuid primary key default gen_random_uuid(), user_id uuid references auth.users not null, url text not null, title text, created_at timestamptz default now() ); alter table links enable row level security; create policy "users can only see their own links" on links for all using (auth.uid() = user_id); Then let Claude Code build the UI: > create app/dashboard/links/page.tsx. Fetch the current user's links from Supabase (server component). Render them in a list. Add a form at the top with a URL input and a title input. The form submission should be a Server Action that inserts a new row into the links table with the current user's id, then revalidatePath('/dashboard/links'). Step 6 — Landing page ----------------------- > create app/page.tsx — a marketing landing page. Hero section with headline "Save links that matter" and a "Get started free" CTA that links to /sign-in. Three feature sections (Clean UI, Private by default, Works everywhere). A simple footer. Tailwind dark theme. At this point, run the dev server: npm run dev Test the full flow manually: landing → sign in → dashboard → add a link → see it appear. Step 7 — Fix the inevitable issues ------------------------------------ Something will be wrong. Common ones: If the OAuth redirect goes to localhost in production: set the NEXT_PUBLIC_APP_URL env var and update the redirectTo to use it. If the Server Action isn't revalidating: make sure revalidatePath is imported from next/cache, not next/navigation. If the middleware redirects are looping: check that your matcher doesn't include /api/auth/callback — that route must be public or the session exchange never completes. Ask Claude Code to fix each issue: > the OAuth redirect is using localhost:3000 even in production. fix it to use NEXT_PUBLIC_APP_URL with a fallback to localhost:3000. Step 8 — Deploy to Vercel --------------------------- npx vercel --prod Set the environment variables in the Vercel dashboard: NEXT_PUBLIC_SUPABASE_URL = from your Supabase project settings NEXT_PUBLIC_SUPABASE_ANON_KEY = from your Supabase project settings NEXT_PUBLIC_APP_URL = https://your-app.vercel.app In your Supabase Auth settings, add the Vercel URL to the allowed redirect URLs. Test the full flow on production. The first deployment often has one env var mistake — Vercel's function logs will tell you exactly which one. What you've learned --------------------- By doing this walkthrough you've experienced: - How to write precise, effective instructions for Claude Code - Where the agent is reliable (boilerplate, patterns, CRUD) vs. where you need to supervise (auth flows, env var wiring) - How skills (nextjs-app-router-pro) pre-load domain context and make the agent faster - The review habit: read every diff, especially on auth-related code The source code for this walkthrough is the kind of thing you could turn into a SKILL.md yourself — "Full-stack Next.js with Supabase auth" as a reusable pattern. That's exactly how the skills marketplace grows. Explore more Next.js skills at claudeskil.com/category/fullstack.