Every app that does something useful stores data. A list of leads. A table of submitted forms. User profiles. Inventory. Whatever it is — it lives in a database, and at some point you have to set one up.
Supabase is the fastest path from "I need a database" to "I have a working database." It gives you a real Postgres database, a visual table editor (so you don't have to write SQL to start), and auto-generated APIs so your app can read and write data with a few lines of code. The free tier is enough to build and ship a real project.
This guide gets you from zero to a connected database you can actually use.
Supabase is hosted Postgres. Postgres is the most widely used open-source relational database — it stores data in tables, rows, and columns, exactly like a spreadsheet but with real query power and data integrity.
What Supabase adds on top of Postgres:
From the dashboard, click New Project. You'll need to:
— Give it a name (your app name is fine)
— Set a database password (use the generated one and save it somewhere — you won't need it often, but you'll want it when you do)
— Choose a region (pick the one closest to your users, or closest to you for development)
Click Create project. It takes about 30 seconds to provision.
Once your project is ready, you'll land on the dashboard. The main navigation is on the left. Click Table Editor.
leads not Leads or LeadsTable.Supabase automatically adds an id column (unique identifier, auto-generated) and a created_at column (timestamp). You just need to add your actual data fields.
Click Add Column for each field you need. For each column, you'll set:
— Name: what the field is called (e.g. email, name, message)
— Type: text for strings, int8 for whole numbers, bool for true/false, timestamptz for dates/times
— Default value and nullable: leave defaults unless you know what you need
A useful mental model: a Supabase table is a spreadsheet where each column has a fixed type. You can add columns later, but you can't easily change a column's type without migrating data. Think through your columns before you start inserting real data.
To connect your app to the database, you need two values: the Project URL and the anon key. These go into your code (or your environment variables) and tell the Supabase client where to connect and how to authenticate.
The Project URL looks like https://abcdefgh.supabase.co. The anon key is a long JWT string. Copy both.
The service_role key on the same page is different — it bypasses all security rules and gives full database access. Never put this in client-side code or commit it to GitHub.
Keep these out of git. Add them to a .env file (and add .env to your .gitignore). The anon key is safe to use in the browser, but your service_role key gives full admin access — treat it like a password.
Install the Supabase JavaScript client in your project:
# In your terminal (Cursor's integrated terminal works fine) npm install @supabase/supabase-js
Then create a Supabase client in your code:
// supabase.js (or db.js — put this in its own file) import { createClient } from '@supabase/supabase-js' const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY export const supabase = createClient(supabaseUrl, supabaseKey)
Now you can use this client anywhere in your app to read or write data:
// Fetch all rows from a table const { data, error } = await supabase .from('leads') .select('*') // Insert a new row const { data, error } = await supabase .from('leads') .insert({ name: 'Jane Smith', email: 'jane@example.com' })
Tip: If you're using Cursor to write the code that connects to Supabase, paste in your table schema (column names and types) in the prompt. Cursor will write the correct insert/select code without guessing at your field names.
By default, Supabase tables are open to anyone who has your anon key. That's fine during development — but before you put a project in front of real users, you want to enable Row Level Security (RLS).
The most common policy for a contact form or lead capture table: allow anonymous INSERT (anyone can submit), but allow SELECT only for authenticated users (so only you can read submissions).
Supabase has policy templates for the most common patterns — you don't need to write the SQL from scratch.
Common beginner mistake: turning on RLS and then wondering why your app stopped working. RLS blocks everything until you add policies. If something breaks after enabling RLS, it means you need to add a policy that explicitly allows that operation.
With a Supabase project set up and connected to your app, you now have the database layer for almost anything:
Next step after this guide: If you've got data in Supabase and a project in Cursor, the next thing to figure out is deployment — getting it live so other people can actually use it. The Vercel + GitHub deployment guide covers exactly that.
On Day 4 of MakerSquare, every student sets up Supabase as the database for their main project. By end of day, they have live data connected to a real app — built, not simulated.