| name | supabase-nextjs-integration |
| description | Use this skill whenever the user wants to set up, refactor, or optimize Supabase usage in a Next.js (App Router) + TypeScript project, including auth, database, storage, RLS-safe patterns, edge functions, and secure client/server integration. |
Supabase + Next.js App Router Integration Skill
Purpose
You are a specialized assistant for integrating Supabase with Next.js App Router in a secure,
idiomatic, and scalable way.
Use this skill to:
- Set up Supabase in a Next.js App Router + TypeScript project
- Configure environment variables & secrets safely
- Create Supabase clients for:
- Server Components
- Route Handlers
- Server Actions
- Client Components (ONLY with anon keys)
- Implement Auth flows (email/password, OAuth, magic links, password reset)
- Use Row Level Security (RLS) safely and correctly
- Integrate database, storage, and edge functions
- Choose between Edge runtime and Node runtime for Supabase usage
- Structure the project so all Supabase usage is consistent and easily testable
Do not use this skill for non-Next.js projects or when Supabase is not part of the stack.
If CLAUDE.md exists, follow its conventions for env vars, directory structure, and security rules
(e.g. “never use service_role in app”, “always go through specific route handlers”).
When To Apply This Skill
Trigger this skill when the user asks for any of the following (or similar):
- “Set up Supabase in this Next.js app.”
- “Use Supabase auth (login, signup, magic links) in my Next.js frontend.”
- “Wire RLS-protected tables to my Next.js pages/components.”
- “Securely call Supabase from server actions / route handlers.”
- “Use Edge Functions from my Next.js app.”
- “Fix Supabase auth/session handling in App Router.”
- “Use Supabase for database + storage + auth in my Next app.”
Avoid applying this skill when:
- The question is purely about UI & components with no data/auth.
- The project does not use or plan to use Supabase.
High-Level Architecture
When integrating Supabase with Next.js App Router, follow this architecture:
Environment & Secrets
Always configure Supabase secrets like this:
# .env.local (never committed)
NEXT_PUBLIC_SUPABASE_URL="https://YOUR_PROJECT_ID.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY="public-anon-key"
SUPABASE_SERVICE_ROLE_KEY="service-role-key" # SERVER ONLY – never exposed client-side
Guidelines:
NEXT_PUBLIC_* env vars are visible to the browser; only use public/anon keys there.
SUPABASE_SERVICE_ROLE_KEY must never be used in code that can run on the client.
- When in doubt, use server components and route handlers to keep secrets safe.
Supabase Client Setup
1. Client-side Supabase (browser / anon-only)
Use this for strictly client-side features that need Supabase and are safe with anon keys
(e.g. some public reads, optional real-time features).
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
Usage in client components:
"use client";
import { useEffect, useState } from "react";
import { createClient } from "@/lib/supabase/client";
export function ProfileWidget() {
const [profile, setProfile] = useState<any>(null);
useEffect(() => {
const supabase = createClient();
supabase
.from("profiles")
.select("*")
.limit(1)
.then(({ data }) => setProfile(data?.[0] ?? null));
}, []);
}
Use this skill to warn when something should really be fetched server-side instead.
2. Server-side Supabase (App Router aware)
Use this in Server Components, Route Handlers, and Server Actions when you need
session-aware Supabase access.
import { cookies } from "next/headers";
import { createServerClient } from "@supabase/ssr";
export function createServerSupabaseClient() {
const cookieStore = cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value;
},
},
}
);
}
Usage in a server component:
import { createServerSupabaseClient } from "@/lib/supabase/server";
export default async function DashboardPage() {
const supabase = createServerSupabaseClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
}
const { data: items } = await supabase.from("items").select("*").order("created_at", { ascending: false });
return <DashboardView user={user} items={items ?? []} />;
}
3. Admin / Service-role Supabase (server-only)
Use sparingly, only for back-office or system tasks that require bypassing RLS.
import { createClient } from "@supabase/supabase-js";
export const adminSupabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: { persistSession: false },
}
);
Never import adminSupabase in client components.
Auth Flows (Next.js + Supabase)
Sign Up / Sign In (Server Actions)
Use server actions or route handlers to handle auth operations:
"use server";
import { redirect } from "next/navigation";
import { createServerSupabaseClient } from "@/lib/supabase/server";
export async function signInWithEmail(formData: FormData) {
const email = String(formData.get("email") ?? "");
const password = String(formData.get("password") ?? "");
const supabase = createServerSupabaseClient();
const { error } = await supabase.auth.signInWithPassword({ email, password });
if (error) {
return { error: error.message };
}
redirect("/dashboard");
}
Use this skill to:
- Keep auth flows entirely server-side where possible.
- Avoid exposing unnecessary auth logic to the client.
- Ensure proper redirects and error handling.
Magic Links / OAuth
- Use Supabase auth methods for magic links and OAuth providers.
- Handle redirect URLs and
next parameters carefully, avoiding open redirects.
RLS (Row Level Security) Best Practices
-
Enable RLS on all tables that store user data.
-
Define policies based on Supabase's auth.uid():
Example policy pattern:
create policy "Users can see their own rows"
on profiles
for select using (
auth.uid() = user_id
);
Use this skill to:
- Encourage RLS for all user-related tables.
- Avoid relying on
service_role for regular app operations.
- Ensure queries are written with RLS in mind (e.g. filter by
user_id instead of trusting client input).
Edge Functions
Supabase Edge Functions are great for:
- High-performance APIs close to your database
- Work that should remain within Supabase infrastructure
Use this skill to:
-
Suggest separation of complex logic into Edge Functions.
-
Show patterns for calling Edge Functions from Next.js via fetch:
const res = await fetch("https://YOUR_PROJECT_ID.supabase.co/functions/v1/my-fn", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(payload),
});
-
Keep security & auth in mind when calling these functions.
Step-by-Step Workflow
When this skill is active, follow this workflow:
1. Detect current state
-
Check if Supabase is already set up:
- Are env vars present?
- Are
@supabase/* dependencies installed?
- Are there any existing Supabase client helper files?
-
If not present → propose a clean setup with minimal, well-structured helpers.
2. Define goals
- Ask (or infer) what the user wants:
- Auth? Database? Storage? Edge Functions?
- RLS on which tables?
- Public vs authenticated routes?
3. Set up or refactor client modules
- Create or refine:
lib/supabase/client.ts
lib/supabase/server.ts
lib/supabase/admin.ts (if needed)
- Ensure no server-only keys are referenced in browser code.
4. Implement auth flows
- For login, signup, logout, password reset, etc.:
- Use server actions or route handlers.
- Maintain a clean separation between UI and auth logic.
- Ensure redirects work correctly in App Router.
5. Wire Supabase into routes/layouts
- Use server components for auth-aware pages and layouts.
- Use RLS-friendly queries (no trusting user IDs from the client).
- Use Suspense/loading states where relevant.
6. Integrate storage & other features
- Provide helpers for uploading/downloading from Supabase storage.
- Ensure signed URL usage when appropriate.
7. Use Edge Functions when appropriate
- Offload complex or latency-sensitive logic.
- Ensure correct authentication from Next.js to Edge Functions.
8. Summarize and document
-
After setting up or refactoring Supabase integration, summarize:
- Where Supabase helpers live.
- How auth flows work.
- How RLS and security are enforced.
- How to add new tables/queries safely.
-
Optionally update README.md or create SUPABASE.md documenting all of the above.
Examples of Prompts That Should Use This Skill
- “Set up Supabase auth and secure dashboard routes in this Next.js app.”
- “Use Supabase with RLS to store user-specific todos and show them in
/dashboard.”
- “Add a profile page reading from the
profiles table with proper auth.”
- “Move this client-side Supabase usage into server components and server actions.”
- “Integrate Supabase Edge Functions for heavy data processing and call them from Next.js.”
- “Refactor our Supabase usage to avoid leaking the service_role key and rely on RLS instead.”
For these tasks, rely on this skill to provide secure, idiomatic Supabase + Next.js App Router integration, and collaborate with other skills (data fetching, performance, testing, routing) as needed.