|
| 1 | +--- |
| 2 | +title: Create your own Supabase Database in 5 minutes |
| 3 | +description: Learn how to create and structure your Supabase database in minutes |
| 4 | +slug: supabase-database-setup |
| 5 | +authors: ozgur |
| 6 | +tags: [supabase, database, backend, tutorial] |
| 7 | +image: https://refine.ams3.cdn.digitaloceanspaces.com/blog/2025-11-17-supabase-tutorial/supabase-tutorial-big.png |
| 8 | +hide_table_of_contents: false |
| 9 | +is_featured: true |
| 10 | +--- |
| 11 | + |
| 12 | +If you’ve ever wanted to create a backend quickly — with a real database, authentication, storage, and auto-generated APIs — **Supabase** is a practical place to start. It’s open source, runs on top of PostgreSQL, and helps you move from idea to data in minutues. |
| 13 | + |
| 14 | +In this guide, we’ll focus entirely on **setting up your Supabase database** — creating tables, understanding relationships, and preparing your project so that tools like **Refine AI** can generate a working admin panel from it. |
| 15 | + |
| 16 | +No frontend, no API calls — just a clear, simple walkthrough of setting up a real, production-grade database the easy way. |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Table of contents |
| 21 | + |
| 22 | +- [Step 1: Create a Supabase Project](#step-1-create-a-supabase-project) |
| 23 | +- [Step 2: Understanding the Table Editor](#step-2-understanding-the-table-editor) |
| 24 | +- [Step 3: Create Your First Table](#step-3-create-your-first-table) |
| 25 | +- [Step 4: Add a Related Table](#step-4-add-a-related-table) |
| 26 | +- [Step 5: Insert Sample Data](#step-5-insert-sample-data) |
| 27 | +- [Step 6: Explore the SQL Editor](#step-6-explore-the-sql-editor) |
| 28 | +- [Step 7: Enable APIs and Policies](#step-7-enable-apis-and-policies) |
| 29 | +- [Why This Matters](#why-this-matters) |
| 30 | +- [What to do after](#what-to-do-after) |
| 31 | +- [Helpful Links](#helpful-links) |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Step 1: Create a Supabase Project |
| 36 | + |
| 37 | +Start at [supabase.com](https://supabase.com) and click **Start your project**. |
| 38 | +You can sign in using GitHub or any email address. |
| 39 | + |
| 40 | +Once you’re in the dashboard, click **New project** and fill in the details: |
| 41 | + |
| 42 | +- **Name** – anything you like, e.g., `team-admin` |
| 43 | +- **Password** – this is your database password (keep it safe!) |
| 44 | +- **Region** – choose one close to you or your users |
| 45 | + |
| 46 | +Then click **Create new project**. |
| 47 | +Within about 30 seconds, you’ll have a live PostgreSQL database running in the cloud — complete with authentication, storage, and instant APIs. |
| 48 | + |
| 49 | +You’ll land on the **project dashboard**, where you’ll see the core sections: |
| 50 | + |
| 51 | +- **Table Editor** – visually manage your database schema |
| 52 | +- **Authentication** – add users and permissions |
| 53 | +- **Storage** – upload and manage files |
| 54 | +- **Edge Functions** – run custom backend logic |
| 55 | + |
| 56 | +For now, we’ll stay inside the **Table Editor**. |
| 57 | + |
| 58 | +--- |
| 59 | + |
| 60 | +## Step 2: Understanding the Table Editor |
| 61 | + |
| 62 | +The [Table Editor](https://supabase.com/docs/guides/database/tables) is where you design your data model. You don’t have to write SQL — though you can, if you want to — Supabase gives you a clean UI for defining everything visually. |
| 63 | + |
| 64 | +Each table is like a spreadsheet, but with types, constraints, and relationships. |
| 65 | + |
| 66 | +When you create a new table, you’ll define: |
| 67 | + |
| 68 | +- **Table name** |
| 69 | +- **Columns** (fields) |
| 70 | +- **Data types** (text, integer, timestamp, etc.) |
| 71 | +- **Default values** and **constraints** |
| 72 | +- **Relationships** (foreign keys) |
| 73 | + Supabase automatically handles the SQL under the hood, and everything you build here instantly becomes accessible through a [REST API](https://supabase.com/docs/guides/api) and [GraphQL](https://supabase.com/docs/guides/api/graphql). |
| 74 | + |
| 75 | +### Row Level Security (RLS) & Policies (Quick Primer) |
| 76 | + |
| 77 | +When you create a table using the Table Editor, **[Row Level Security (RLS)](https://supabase.com/docs/guides/database/postgres/row-level-security)** is enabled by default. With RLS enabled and **no policies**, any request through the REST or GraphQL APIs (using the public `anon` key) returns **no rows**. Policies are Postgres rules that act like implicit `WHERE` clauses for each operation (`SELECT`, `INSERT`, `UPDATE`, `DELETE`). You’ll add policies later to selectively open access. |
| 78 | + |
| 79 | +Role mapping: |
| 80 | + |
| 81 | +- `anon`: requests without a user JWT (public key only) |
| 82 | +- `authenticated`: requests with a valid user JWT (including “anonymous sessions” created via Supabase Auth; those still assume the `authenticated` role) |
| 83 | + |
| 84 | +You can always inspect or change RLS via the table’s Policies tab (see the [RLS guide](https://supabase.com/docs/guides/database/postgres/row-level-security) for details). We’ll keep schema focus first, then add policies once structure exists. |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## Step 3: Create Your First Table |
| 89 | + |
| 90 | +Let’s create a simple `employees` table — a common resource you might manage later in Refine AI. |
| 91 | + |
| 92 | +1. In the **Table Editor**, click **New Table**. |
| 93 | +2. Name it `employees`. |
| 94 | +3. Add the following columns: |
| 95 | + |
| 96 | +| Column | Type | Default | Notes | |
| 97 | +| ------------ | --------------- | ------------------- | --------------------------------------------------------------------------------------------------- | |
| 98 | +| `id` | `uuid` | `gen_random_uuid()` | Primary key | |
| 99 | +| `name` | `text` | — | Employee name | |
| 100 | +| `role` | `text` | — | Job title or position | |
| 101 | +| `salary` | `numeric(12,2)` | — | Optional salary field (consider storing minor units as integer if you need strict money arithmetic) | |
| 102 | +| `created_at` | `timestamptz` | `now()` | Record creation time | |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | +:::tip |
| 107 | +The “Enable Row Level Security” toggle is ON by default in the Table Editor. Leave it enabled—your table is protected until you add explicit policies. |
| 108 | +::: |
| 109 | + |
| 110 | +Click **Save**. Your table is created instantly and available via REST (once policies allow it). |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +## Step 4: Add a Related Table |
| 115 | + |
| 116 | +Let’s make another table called `departments` so you can see how relationships work. |
| 117 | + |
| 118 | +1. Click **New Table**, name it `departments`. |
| 119 | +2. Add: |
| 120 | + |
| 121 | +| Column | Type | Default | |
| 122 | +| ------ | ------ | ------------------- | |
| 123 | +| `id` | `uuid` | `gen_random_uuid()` | |
| 124 | +| `name` | `text` | — | |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | +Now go back to your `employees` table and click **Add Column** → name it `department_id`. |
| 129 | +Set its **type** to `uuid`, and under **Foreign Key**, select **departments → id**. For safer deletes, set the FK behavior to **ON DELETE SET NULL**. |
| 130 | + |
| 131 | +Click **Save** again. |
| 132 | + |
| 133 | +You’ve just created your first relational link — every employee belongs to a department. Supabase automatically handles referential integrity and updates your schema. |
| 134 | + |
| 135 | +This structure is now ready for Refine AI to analyze later and generate fully functional list, create, and edit pages for you. |
| 136 | + |
| 137 | +--- |
| 138 | + |
| 139 | +## Step 5: Insert Sample Data |
| 140 | + |
| 141 | +In the **Table Editor**, click on your `departments` table and choose **Insert Row**. |
| 142 | +Add a few examples: |
| 143 | + |
| 144 | + |
| 145 | +| id | name | |
| 146 | +| ------ | ----------- | |
| 147 | +| (auto) | Engineering | |
| 148 | +| (auto) | Marketing | |
| 149 | +| (auto) | HR | |
| 150 | + |
| 151 | +Then go to your `employees` table and insert: |
| 152 | + |
| 153 | + |
| 154 | +| id | name | role | salary | department_id | |
| 155 | +| ------ | ----- | ------------- | ------ | ---------------- | |
| 156 | +| (auto) | Alice | Engineer | 85000 | (Engineering id) | |
| 157 | +| (auto) | Bob | HR Specialist | 60000 | (HR id) | |
| 158 | + |
| 159 | +Your data is now live. |
| 160 | +You can view, edit, and filter it right in the dashboard — or query it using SQL in the **SQL Editor** tab. |
| 161 | + |
| 162 | +--- |
| 163 | + |
| 164 | +## Step 6: Explore the SQL Editor |
| 165 | + |
| 166 | +Even though the Table Editor is visual, Supabase lets you use full PostgreSQL SQL if you prefer. Click the **[SQL Editor](https://supabase.com/docs/guides/database/overview#the-sql-editor)** tab in the sidebar. |
| 167 | + |
| 168 | +Here you can: |
| 169 | + |
| 170 | +- Run queries like `SELECT * FROM employees;` |
| 171 | +- Create views, triggers, and functions |
| 172 | +- Save and version your SQL scripts |
| 173 | + |
| 174 | +For example, once you’ve inserted `departments` and linked employees with a real `department_id`, try: |
| 175 | + |
| 176 | + |
| 177 | +```sql |
| 178 | +SELECT e.name, e.role, d.name AS department |
| 179 | +FROM public.employees e |
| 180 | +LEFT JOIN public.departments d ON e.department_id = d.id; |
| 181 | +``` |
| 182 | + |
| 183 | +:::warning Relation not found (42P01) |
| 184 | +If you see `ERROR: 42P01: relation "public.employees" does not exist`: |
| 185 | + |
| 186 | +- Ensure you clicked Save when creating the table. |
| 187 | +- Confirm the schema is `public` (default) and the table name is lowercase `employees`. |
| 188 | +- Refresh the browser tab—occasionally the SQL Editor metadata lags. |
| 189 | +- Verify you’re in the same project where the table was created. |
| 190 | + ::: |
| 191 | + |
| 192 | +:::tip No results or NULL department values? |
| 193 | +`LEFT JOIN` will keep employees visible even when `department_id` isn’t set yet. To see department names, edit the employee and paste the UUID of the correct department into `department_id`. |
| 194 | +::: |
| 195 | + |
| 196 | +## This flexibility means you can build relational structures that Refine AI (or any frontend) can use directly. |
| 197 | + |
| 198 | +## Step 7: Enable APIs and Policies |
| 199 | + |
| 200 | +Every table you create in an exposed schema automatically has a REST endpoint, e.g.: |
| 201 | + |
| 202 | +``` |
| 203 | +https://<project-ref>.supabase.co/rest/v1/employees |
| 204 | +``` |
| 205 | + |
| 206 | +View API examples and keys under Project Settings → API Docs (see the [API overview](https://supabase.com/docs/guides/api)). |
| 207 | + |
| 208 | +Because RLS is enabled, you must add policies before data is visible. Using the **Policies** tab in a table: |
| 209 | + |
| 210 | +1. Open `employees` → Policies → New Policy. |
| 211 | +2. Choose operation: SELECT. |
| 212 | +3. Template: “Allow authenticated users” (or create custom). |
| 213 | +4. Save. The UI shows the SQL for reference. |
| 214 | + |
| 215 | +Resulting read policy: |
| 216 | + |
| 217 | +```sql |
| 218 | +create policy "Authenticated can read employees" |
| 219 | +on public.employees |
| 220 | +for select |
| 221 | +to authenticated |
| 222 | +using (true); |
| 223 | +``` |
| 224 | + |
| 225 | +Insert policy (allow authenticated users to add rows): |
| 226 | + |
| 227 | +```sql |
| 228 | +create policy "Enable insert for authenticated users only" |
| 229 | +on public.employees |
| 230 | +for insert |
| 231 | +to authenticated |
| 232 | +with check (true); |
| 233 | +``` |
| 234 | + |
| 235 | + |
| 236 | + |
| 237 | +Optional (dev only) broader read access: |
| 238 | + |
| 239 | +```sql |
| 240 | +create policy "Dev read employees (anon + authenticated)" |
| 241 | +on public.employees |
| 242 | +for select |
| 243 | +to anon, authenticated |
| 244 | +using (true); |
| 245 | +``` |
| 246 | + |
| 247 | +Remove permissive policies before production. |
| 248 | + |
| 249 | +Role nuance: |
| 250 | + |
| 251 | +- Requests without a JWT use the `anon` role. |
| 252 | +- Authenticated user sessions (including Supabase’s [anonymous auth](https://supabase.com/docs/guides/auth/auth-anonymous) sessions) map to `authenticated`. |
| 253 | +- `auth.uid()` is `NULL` for unauthenticated requests—combine with checks like `auth.uid() IS NOT NULL` for clarity. |
| 254 | + |
| 255 | +REST example (after policies): |
| 256 | + |
| 257 | +```bash |
| 258 | +curl -H "apikey: $SUPABASE_ANON_KEY" \ |
| 259 | + -H "Authorization: Bearer $USER_JWT" \ |
| 260 | + "https://<project-ref>.supabase.co/rest/v1/employees?select=*" |
| 261 | +``` |
| 262 | + |
| 263 | +You can layer more granular policies later (row ownership, role-based filters, etc.). |
| 264 | + |
| 265 | +--- |
| 266 | + |
| 267 | +## Why This Matters |
| 268 | + |
| 269 | +The old way of setting up databases meant provisioning servers, installing PostgreSQL, managing connections, and writing migration scripts. Supabase makes the setup much simpler. |
| 270 | + |
| 271 | +Within minutes, you can have: |
| 272 | + |
| 273 | +- A structured PostgreSQL database |
| 274 | +- Relationships and constraints |
| 275 | +- Realtime APIs |
| 276 | +- Secure authentication |
| 277 | + |
| 278 | +Supabase also works well with **Refine AI** — once your schema is ready, Refine AI can generate an admin UI around it: tables, forms, relationships, and filters. |
| 279 | + |
| 280 | +--- |
| 281 | + |
| 282 | +## What to do after |
| 283 | + |
| 284 | +The quickest win now is to connect your Supabase database to Refine AI and generate working internal tools (admin panel, CRUD, filters, relations) from your schema in minutes. See the walkthrough: |
| 285 | + |
| 286 | +- Build internal tools from your Supabase schema → https://refine.dev/blog/supabase-refine-ai/ |
| 287 | + |
| 288 | +--- |
| 289 | + |
| 290 | +## Helpful Links |
| 291 | + |
| 292 | +- [Supabase Docs](https://supabase.com/docs) – explore all features |
| 293 | +- [Supabase SQL Editor](https://supabase.com/docs/guides/database/overview#the-sql-editor) – learn to write queries |
| 294 | +- [Supabase Auth](https://supabase.com/docs/guides/auth) – configure access and security policies |
| 295 | +- [Local Development & CLI](https://supabase.com/docs/guides/local-development/overview) – run Supabase locally with migrations |
| 296 | +- [Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security) – how to enable and write policies |
| 297 | +- [Refine + Supabase Guide](https://refine.dev/docs/guides/supabase) – connect your schema to Refine AI |
| 298 | +- [Supabase Discord](https://discord.supabase.com) – join the community |
| 299 | + |
| 300 | +--- |
0 commit comments