How to set up a Supabase project
Status: 🟩 COMPLETE Last updated: 2026-06-19 Plain-English tagline: New Supabase project, env vars, first table, first RLS policy — from zero to a working backend in ~15 minutes.
Goal
You have a Next.js (or any web) project that needs a backend: database, auth, storage. At the end of this guide, your project has a live Supabase backend, your local app can connect to it, and a first table is set up with proper Row-Level Security.
Prerequisites
- Supabase account — free at supabase.com
- A local web project (e.g. a Next.js app) where you’ll connect Supabase
- Node.js installed
- A region in mind — pick the one nearest your users (e.g.
syd1for Sydney)
Steps
1. Create the Supabase project
- Go to app.supabase.com and click New project.
- Pick an organization (or create one for your personal projects).
- Enter:
- Name — anything memorable
- Database password — generate a strong one and save it in a password manager (you’ll occasionally need it for direct DB connections)
- Region — match this to where your hosting (e.g. Vercel) will run. For Australia:
Southeast Asia (Singapore)or wait for the Sydney option if available. For US:East US (N. Virginia)is the default Vercel matches. - Pricing plan — Free is fine for starters
- Click Create new project. Provisioning takes ~1–2 minutes.
2. Grab your API URL and keys
Once provisioning is done:
- In your Supabase project, go to Settings → API.
- Copy:
- Project URL (looks like
https://xxxxxxxx.supabase.co) - anon (public) key (safe to expose in client code)
- service_role (secret) key — NEVER expose this; server-side only
- Project URL (looks like
3. Add env vars to your local project
In your project root, create .env.local (gitignored by default in Next.js):
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGc...
# Server-only — NO NEXT_PUBLIC_ prefix
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...Critical: The NEXT_PUBLIC_ prefix exposes a variable to the browser. The anon key is OK there because it’s restricted by Row-Level Security. The service_role key bypasses ALL security — it must NEVER have a NEXT_PUBLIC_ prefix.
4. Install the SDK
npm install @supabase/supabase-js @supabase/ssrThe @supabase/ssr package is the helper for server-side rendering in Next.js (handles session cookies correctly).
5. Create a Supabase client helper
For Client Components, create 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!
);
}For Server Components / Server Actions / Route Handlers, create lib/supabase-server.ts:
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll: () => cookieStore.getAll(),
setAll: (cookiesToSet) => {
cookiesToSet.forEach(({ name, value, options }) => {
cookieStore.set(name, value, options);
});
}
}
}
);
}6. Create your first table
In Supabase: SQL Editor → New query. Paste and run:
CREATE TABLE posts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
title text NOT NULL,
body text,
created_at timestamptz DEFAULT now()
);
-- Enable Row-Level Security (CRITICAL — don't skip!)
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- For now, let anyone read posts:
CREATE POLICY "Anyone can read posts"
ON posts FOR SELECT
USING (true);7. Test the connection from your app
In a Server Component:
// app/page.tsx
import { createClient } from "@/lib/supabase-server";
export default async function HomePage() {
const supabase = await createClient();
const { data: posts, error } = await supabase.from("posts").select("*");
if (error) return <p>Error: {error.message}</p>;
return (
<main>
<h1>Posts</h1>
{posts?.length === 0 && <p>(no posts yet)</p>}
{posts?.map((p) => (
<article key={p.id}>
<h2>{p.title}</h2>
<p>{p.body}</p>
</article>
))}
</main>
);
}Add a test row via the Table Editor in Supabase, then run npm run dev. The page should show it.
Verification
- âś… Supabase project shows as Healthy in the dashboard
- âś…
.env.localhas the URL andanonkey (NOT theservice_rolekey withNEXT_PUBLIC_prefix) - âś… Local dev server loads without errors
- âś… The post you added via the Table Editor shows on the homepage
Common failures
”process.env.NEXT_PUBLIC_SUPABASE_URL is undefined”
You probably forgot to restart the dev server after editing .env.local. Next.js only reads env files on startup. Kill the server, run npm run dev again.
”Invalid API key”
Either:
- You copied the wrong key (mixed up
anonandservice_role) - The variable name in
.env.localdoesn’t match what your code uses - A typo somewhere — env-var names are case-sensitive
Table exists but select("*") returns empty
Almost always: RLS is enabled but no policy allows SELECT. Either add the policy (step 6) or temporarily disable RLS to test, then re-enable.
CORS errors
Supabase allows your local origin (http://localhost:3000) by default. If you’ve set up a custom domain or are running on a non-default port and see CORS issues, add the origin in Settings → API → CORS allowed origins.
Region latency
If your Supabase project is in the US but you’re testing from Australia, every query has ~200ms round-trip. Normal for dev; pin Vercel functions to the same region for production.
What you’ve just built
A working Supabase backend wired into your Next.js app:
- Live Postgres database
- Auto-generated REST + GraphQL APIs
- Auth scaffolding ready (next how-to)
- Row-Level Security enabled by default (one policy added so far)
- Two client patterns (browser + server) using the modern
@supabase/ssrSDK
You can now:
- Add more tables in the SQL Editor
- Write more RLS policies as needed
- Set up auth (see Add Supabase auth)
- Deploy to Vercel — env vars carry over (after you set them in the Vercel dashboard)
See also
- Supabase 🟩 🟦
- Row-Level Security 🟥
- How-to: Add Supabase auth đźź©
- How-to: Enable RLS đźź©
- Next.js 🟩 🟦
- Environment variables 🟥
- Supabase gotchas 🟥