Connecting Supabase to Your Next.js App
You have a database and a table. Now you'll plug your Next.js app into it. Three things happen here: you store your keys safely, you install the Supabase library, and you let Claude create the connection code. Then you confirm it works.
Step 1: Store Your Keys in an Environment File
Your app needs to know your Supabase URL and anon key. These live in a file called .env.local, which sits in your project folder and never gets committed to GitHub.
In your terminal, inside your project folder:
touch .env.local
Open it in VS Code (code .) and add your two values from Settings → API:
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
Replace both with your actual values.
Why the NEXT_PUBLIC_ prefix?
In Next.js, any environment variable starting with NEXT_PUBLIC_ is bundled into the browser, where anyone can read it. That's fine here — the anon key is designed to be public and is protected by your RLS policies.
The line you must never cross. A true secret — like the Supabase
service_rolekey — must never get aNEXT_PUBLIC_prefix and must never sit in client-side code. Putting theservice_rolekey in aNEXT_PUBLIC_variable would hand every visitor a master key that bypasses all your security rules. Only the anon key belongs in the browser.
Your .env.local should already be listed in .gitignore. Confirm it is before you ever push to GitHub.
Step 2: Install the Supabase Library
In your terminal, inside your project folder:
npm install @supabase/supabase-js @supabase/ssr
This installs:
@supabase/supabase-js— the main Supabase JavaScript library@supabase/ssr— helpers for using Supabase with Next.js server-side rendering and cookies (needed for login to work smoothly later)
Step 3: Let Claude Create the Connection Code
You need a small utility file that initializes the Supabase connection. Let Claude write it:
Set up Supabase in my Next.js project.
Create these files:
utils/supabase/client.ts— a Supabase browser client for client componentsutils/supabase/server.ts— a Supabase server client for server components and API routesUse the
@supabase/ssrpackage for the server client so cookies are handled correctly.My environment variables are
NEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEY.
The browser client Claude generates will look roughly like this — you don't write it, but it's good to recognize:
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Notice it only ever reads the two NEXT_PUBLIC_ (anon) values. That's correct — the browser client should never see anything more privileged.
⚡ Or let Claude Code do Steps 1–3
Creating the env file, installing the libraries, and writing the client code can all be handed to Claude Code in one go. In your project's Claude Code session, paste:
Set up Supabase in this Next.js project:
1. Install the @supabase/supabase-js and @supabase/ssr packages.
2. Create a .env.local with NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY
as empty placeholders, and make sure .env.local is in .gitignore.
3. Create utils/supabase/client.ts (a browser client) and utils/supabase/server.ts
(a server client) using the @supabase/ssr package.
Don't put any real keys in the code — I'll paste my own URL and anon key into .env.local.
You'll still open .env.local and paste in your actual URL and anon key — those are real secrets, so you handle them, not Claude. Everything else it does for you. Read the manual steps above so you understand what each file is for.
Step 4: Restart Your Dev Server
This is the single most common gotcha in this entire module. Next.js only reads .env.local when the server starts. After creating or editing that file, you must restart:
# Stop the server
Ctrl + C
# Start it again
npm run dev
If something acts strange right after you touch environment variables, restart first and re-check second.
Step 5: Test the Connection
Ask Claude to add a throwaway test so you can confirm the link works:
Add a temporary test to my home page that fetches data from the
taskstable in Supabase and logs the result to the console. This is just to verify the connection — I'll replace it with real functionality next.
Then:
- Open
http://localhost:3000 - Open the browser developer console (right-click → Inspect → Console tab)
You should see one of two things:
- An array of tasks — probably empty:
[]. That means the connection works. An empty list is success; it just means the table has no rows yet. - An error message — something needs fixing (see below)
Common Connection Errors
| Error | What it usually means | Fix |
|---|---|---|
Invalid API key | A typo or stray space in .env.local, or the server wasn't restarted | Re-copy the anon key, check for spaces, restart the dev server |
relation "tasks" does not exist | The table wasn't created, or the name differs | Confirm the table name in the Supabase Table Editor |
Empty [] with no error | Nothing wrong — RLS is on and there are no rows you can see yet | Add a row, or move on to the CRUD lesson |
Once you've confirmed it works, ask Claude to remove the temporary test.
Client vs. Server Components (The Short Version)
Next.js has two kinds of components, and they use two different Supabase clients:
| Client Components | Server Components | |
|---|---|---|
| Marked with | "use client" at the top | nothing (the default) |
| Runs in | the browser | the server |
| Can use | useState, useEffect, click handlers | direct data fetching, no loading spinner needed |
| Supabase client | the browser client | the server client |
| Security | uses the public anon key | keys never reach the browser |
For your first app, using client components throughout is perfectly fine. As you get comfortable, Claude can help you move heavy data fetching to server components for better performance and security.
Telling Claude What to Build Next
Once the connection is live, describe the feature you want wired to real data. A template that works well:
Now that Supabase is connected, update [specific feature] to use real data.
Current behavior: tasks are hardcoded example data. Desired behavior: tasks are fetched from the
taskstable in Supabase.The
taskstable has:id,title,done,user_id,created_at.For now, skip authentication — just fetch all tasks (no user filtering yet). We'll add auth later.
Summary
- Store your URL and anon key in
.env.local(with theNEXT_PUBLIC_prefix) and never commit it. - Only the anon key belongs in the browser; the
service_rolekey never gets aNEXT_PUBLIC_prefix or client-side code. - Install with
npm install @supabase/supabase-js @supabase/ssr. - Let Claude create the browser and server client utility files.
- Restart the dev server after any change to
.env.local. - Test by logging a fetch to the console — an empty
[]means success.