The Supabase SQL Editor is a built-in browser tool in the Dashboard where you can write and run any PostgreSQL query directly against your database. Open it from the left sidebar, type your SQL, and click Run or press Cmd+Enter. You can save queries as snippets, export results to CSV, browse your schema, and use it for everything from creating tables to debugging RLS policies.
Using the SQL Editor in the Supabase Dashboard
The SQL Editor is one of the most powerful tools in the Supabase Dashboard. It gives you direct PostgreSQL access without needing a terminal or external database client. You can create tables, write complex queries, debug Row Level Security policies, manage indexes, and run migrations — all from your browser. This tutorial walks you through the full workflow from opening the editor to saving and exporting your queries.
Prerequisites
- A Supabase project (free tier works)
- Access to the Supabase Dashboard at app.supabase.com
- Basic understanding of SQL syntax (SELECT, INSERT, UPDATE, DELETE)
Step-by-step guide
Open the SQL Editor in the Dashboard
Open the SQL Editor in the Dashboard
Log in to your Supabase Dashboard at app.supabase.com and select your project. In the left sidebar, click the SQL Editor icon (it looks like a terminal/code icon). This opens the SQL Editor view with a blank query tab. You can have multiple query tabs open at once — each tab is an independent query workspace. The left panel shows your saved snippets and quickstart templates provided by Supabase.
Expected result: The SQL Editor opens with a blank query tab and a blinking cursor ready for input.
Write and run your first SELECT query
Write and run your first SELECT query
Type a SQL query in the editor area. Start with a simple SELECT to verify your setup. Click the green Run button in the top-right corner or press Cmd+Enter (Mac) / Ctrl+Enter (Windows) to execute. The results appear in a table below the editor. You can sort columns by clicking their headers and resize columns by dragging the borders. If your query has an error, the error message appears in red below the editor with the line number and description.
1-- List all tables in the public schema2SELECT table_name, table_type3FROM information_schema.tables4WHERE table_schema = 'public'5ORDER BY table_name;67-- Query data from a specific table8SELECT *9FROM your_table_name10LIMIT 20;Expected result: A results table appears below the editor showing the query output with column headers and row data.
Use the schema browser to explore tables and columns
Use the schema browser to explore tables and columns
On the left side of the SQL Editor, switch to the schema browser panel. This shows all schemas (public, auth, storage, etc.) and the tables within each schema. Expand a table to see its columns, data types, and constraints. This is invaluable when you need to check column names or data types before writing a query. You can also see indexes, triggers, and foreign key relationships directly in the browser.
1-- You can also explore your schema with SQL2SELECT column_name, data_type, is_nullable, column_default3FROM information_schema.columns4WHERE table_schema = 'public'5 AND table_name = 'your_table_name'6ORDER BY ordinal_position;Expected result: The schema browser displays your tables, columns, and their data types in a tree view.
Create a table using the SQL Editor
Create a table using the SQL Editor
The SQL Editor is the recommended way to create tables when you need precise control over data types, constraints, and defaults. Write a CREATE TABLE statement, enable Row Level Security immediately after creation, and add at least one RLS policy so the table is accessible via the API. Always enable RLS on any table exposed through the public schema — without it, anyone with your anon key can read all data.
1-- Create a tasks table2CREATE TABLE public.tasks (3 id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,4 user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,5 title text NOT NULL,6 completed boolean DEFAULT false,7 created_at timestamptz DEFAULT now()8);910-- Enable Row Level Security11ALTER TABLE public.tasks ENABLE ROW LEVEL SECURITY;1213-- Allow users to read their own tasks14CREATE POLICY "Users can view own tasks"15 ON public.tasks FOR SELECT16 TO authenticated17 USING ((SELECT auth.uid()) = user_id);1819-- Allow users to insert their own tasks20CREATE POLICY "Users can create tasks"21 ON public.tasks FOR INSERT22 TO authenticated23 WITH CHECK ((SELECT auth.uid()) = user_id);Expected result: The table is created with RLS enabled and policies applied. You can verify by checking the Table Editor in the Dashboard sidebar.
Save queries as reusable snippets
Save queries as reusable snippets
After writing a query you want to reuse, click the Save button (or use Cmd+S) to save it as a snippet. Give it a descriptive name like 'List active users' or 'Monthly revenue report'. Saved snippets appear in the left panel under your personal snippets. You can also create folders to organize them. Snippets are saved per-user, not per-project, so only you can see your saved queries. To share a query with your team, copy the SQL and share it as a migration file instead.
Expected result: Your query appears in the saved snippets panel and can be opened in a new tab at any time.
Export query results to CSV
Export query results to CSV
After running a query, you can export the results by clicking the Download button (downward arrow icon) above the results table. This exports the current result set as a CSV file. This is useful for sharing data with non-technical team members, creating reports, or backing up small datasets. For large exports (millions of rows), use pg_dump from the command line instead — the SQL Editor export works best for result sets under 100,000 rows.
1-- Example: Export all users who signed up this month2SELECT3 id,4 email,5 created_at,6 raw_user_meta_data->>'first_name' AS first_name7FROM auth.users8WHERE created_at >= date_trunc('month', CURRENT_DATE)9ORDER BY created_at DESC;Expected result: A CSV file downloads to your computer containing the query results with column headers.
Complete working example
1-- =============================================2-- Supabase SQL Editor: Common Query Examples3-- =============================================45-- 1. Create a table with proper constraints6CREATE TABLE public.projects (7 id uuid PRIMARY KEY DEFAULT gen_random_uuid(),8 user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,9 name text NOT NULL CHECK (char_length(name) > 0),10 description text,11 status text DEFAULT 'active' CHECK (status IN ('active', 'archived', 'deleted')),12 created_at timestamptz DEFAULT now(),13 updated_at timestamptz DEFAULT now()14);1516-- 2. Enable RLS (always do this for public tables)17ALTER TABLE public.projects ENABLE ROW LEVEL SECURITY;1819-- 3. Create RLS policies20CREATE POLICY "Users can view own projects"21 ON public.projects FOR SELECT TO authenticated22 USING ((SELECT auth.uid()) = user_id);2324CREATE POLICY "Users can insert own projects"25 ON public.projects FOR INSERT TO authenticated26 WITH CHECK ((SELECT auth.uid()) = user_id);2728CREATE POLICY "Users can update own projects"29 ON public.projects FOR UPDATE TO authenticated30 USING ((SELECT auth.uid()) = user_id)31 WITH CHECK ((SELECT auth.uid()) = user_id);3233CREATE POLICY "Users can delete own projects"34 ON public.projects FOR DELETE TO authenticated35 USING ((SELECT auth.uid()) = user_id);3637-- 4. Add an index for faster queries38CREATE INDEX idx_projects_user_id ON public.projects (user_id);3940-- 5. Create an auto-update trigger for updated_at41CREATE OR REPLACE FUNCTION public.update_updated_at()42RETURNS TRIGGER43LANGUAGE plpgsql44AS $$45BEGIN46 NEW.updated_at = now();47 RETURN NEW;48END;49$$;5051CREATE TRIGGER set_updated_at52 BEFORE UPDATE ON public.projects53 FOR EACH ROW54 EXECUTE FUNCTION public.update_updated_at();5556-- 6. Query with filters and joins57SELECT58 p.id,59 p.name,60 p.status,61 p.created_at,62 u.email AS owner_email63FROM public.projects p64JOIN auth.users u ON u.id = p.user_id65WHERE p.status = 'active'66ORDER BY p.created_at DESC67LIMIT 50;Common mistakes when writing SQL Queries in the Supabase SQL Editor
Why it's a problem: Forgetting to enable RLS after creating a table in the SQL Editor
How to avoid: Always add ALTER TABLE your_table ENABLE ROW LEVEL SECURITY immediately after CREATE TABLE. Without RLS, anyone with your anon key can read and modify all rows.
Why it's a problem: Running destructive queries (DROP TABLE, DELETE without WHERE) without a backup
How to avoid: Always run a SELECT with the same WHERE clause first to preview which rows will be affected. For DROP operations, consider renaming the table first as a soft-delete.
Why it's a problem: Trying to modify the auth schema directly (INSERT INTO auth.users)
How to avoid: Use the Supabase Auth API (supabase.auth.signUp, supabase.auth.admin.createUser) instead. The auth schema is managed by GoTrue and direct modification can break authentication.
Why it's a problem: Writing queries that reference non-existent columns because of a typo
How to avoid: Use the schema browser to verify column names before writing queries. Column names in Supabase are case-sensitive if quoted — prefer lowercase_with_underscores and never quote identifiers.
Best practices
- Always enable RLS on every table in the public schema and create appropriate policies before using the table in production
- Use the SELECT preview technique before running UPDATE or DELETE — write a SELECT with the same WHERE clause first
- Save frequently used queries as snippets so you do not have to rewrite them each time
- Add comments to your SQL queries explaining what they do and why, especially for complex JOINs and RLS policies
- Use LIMIT when exploring large tables to avoid loading millions of rows into the editor
- Prefer gen_random_uuid() for primary keys in new tables — it avoids sequential ID enumeration attacks
- Create indexes on columns used in WHERE clauses and RLS policies to keep queries fast
- Use transactions (BEGIN; ... COMMIT;) when running multiple related changes to ensure atomicity
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I need to write a SQL query in the Supabase SQL Editor that creates a table for blog posts with a title, body, author (linked to auth.users), published status, and timestamps. Include RLS policies so users can only see and edit their own posts. Show the complete SQL.
Write a SQL query in the Supabase SQL Editor to create a blog_posts table with columns for id (UUID), user_id (foreign key to auth.users), title (text), body (text), is_published (boolean), and created_at (timestamptz). Enable RLS and add policies for authenticated users to CRUD their own posts.
Frequently asked questions
Can I run multiple SQL statements in one query tab?
Yes. Separate statements with semicolons and click Run to execute all of them in order. You can also highlight a single statement and press Cmd+Enter to run only that statement.
Is there a query size or result limit in the SQL Editor?
The SQL Editor works best with result sets under 100,000 rows. For larger exports, use pg_dump from the CLI. There is no hard query size limit, but very long queries may time out after 60 seconds on the free plan.
Can I access the auth.users table from the SQL Editor?
Yes, you can SELECT from auth.users in the SQL Editor to inspect user data. However, never INSERT, UPDATE, or DELETE rows in auth.users directly — use the Supabase Auth API or the Dashboard Authentication panel instead.
How do I undo a query I ran by mistake?
SQL queries in the editor are not automatically reversible. For DML changes (INSERT, UPDATE, DELETE), you would need a backup or point-in-time recovery (Pro plan). For DDL changes (DROP TABLE), restore from a backup. Always test destructive queries on a local Supabase instance first.
Can I use the SQL Editor to debug Row Level Security policies?
Yes. You can test RLS by running queries as different roles. Use SET ROLE authenticated followed by SET request.jwt.claims to simulate a specific user. This helps verify that policies return the correct rows.
Does the SQL Editor support autocomplete?
The SQL Editor provides basic autocomplete for SQL keywords and table names. It is not as advanced as desktop tools like DataGrip, but it covers common use cases. Use the schema browser alongside the editor for column name reference.
Can RapidDev help me write complex SQL queries for my Supabase project?
Yes. RapidDev's engineering team can help you design database schemas, write complex queries, set up RLS policies, and optimize performance for your Supabase project.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation