| 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 variables
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEY(server-only, NEVER sent to client)- Any other Supabase-related secrets (e.g. JWT secret, webhook secrets)
Supabase client modules (example paths):
src/lib/supabase/client.ts→ browser/client-side usage (anon key)src/lib/supabase/server.ts→ server-side usage with cookies & auth helperssrc/lib/supabase/admin.ts→ server-only admin usage (service_role, if really needed)
Auth integration
- Use Supabase auth for sessions and user identity.
- Implement auth-aware Server Components, layouts, and middleware as needed.
- Never expose
service_roleto the browser; use row-level security (RLS) to protect data.
Edge vs Node runtime
- Use Edge runtime (
runtime = "edge") when you want low-latency Supabase access and your libraries are Edge-compatible. - Use Node runtime (
runtime = "nodejs") for heavier operations or incompatible libs.
- Use Edge runtime (
Edge Functions
- Implement Supabase Edge Functions for server-side logic that should run close to the data
and call them from your Next.js app via
fetch.
- Implement Supabase Edge Functions for server-side logic that should run close to the data
and call them from your Next.js app via
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_KEYmust 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).
// src/lib/supabase/client.ts
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));
}, []);
// render...
}
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.
// src/lib/supabase/server.ts
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:
// app/dashboard/page.tsx
import { createServerSupabaseClient } from "@/lib/supabase/server";
export default async function DashboardPage() {
const supabase = createServerSupabaseClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
// handle redirect to login, etc.
}
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.
// src/lib/supabase/admin.ts
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:
// app/(auth)/actions.ts
"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) {
// handle error (return structured 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
nextparameters 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_rolefor regular app operations. - Ensure queries are written with RLS in mind (e.g. filter by
user_idinstead 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}`, // if needed }, 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.tslib/supabase/server.tslib/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.mdor createSUPABASE.mddocumenting 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
profilestable 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.