# How to Write SQL Queries in the Supabase SQL Editor

- Tool: Supabase
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: Supabase (all plans), Dashboard SQL Editor
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

### 2. 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.

```
-- List all tables in the public schema
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name;

-- Query data from a specific table
SELECT *
FROM your_table_name
LIMIT 20;
```

**Expected result:** A results table appears below the editor showing the query output with column headers and row data.

### 3. 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.

```
-- You can also explore your schema with SQL
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
  AND table_name = 'your_table_name'
ORDER BY ordinal_position;
```

**Expected result:** The schema browser displays your tables, columns, and their data types in a tree view.

### 4. 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.

```
-- Create a tasks table
CREATE TABLE public.tasks (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  title text NOT NULL,
  completed boolean DEFAULT false,
  created_at timestamptz DEFAULT now()
);

-- Enable Row Level Security
ALTER TABLE public.tasks ENABLE ROW LEVEL SECURITY;

-- Allow users to read their own tasks
CREATE POLICY "Users can view own tasks"
  ON public.tasks FOR SELECT
  TO authenticated
  USING ((SELECT auth.uid()) = user_id);

-- Allow users to insert their own tasks
CREATE POLICY "Users can create tasks"
  ON public.tasks FOR INSERT
  TO authenticated
  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.

### 5. 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.

### 6. 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.

```
-- Example: Export all users who signed up this month
SELECT
  id,
  email,
  created_at,
  raw_user_meta_data->>'first_name' AS first_name
FROM auth.users
WHERE created_at >= date_trunc('month', CURRENT_DATE)
ORDER BY created_at DESC;
```

**Expected result:** A CSV file downloads to your computer containing the query results with column headers.

## Complete code example

File: `sql-editor-examples.sql`

```sql
-- =============================================
-- Supabase SQL Editor: Common Query Examples
-- =============================================

-- 1. Create a table with proper constraints
CREATE TABLE public.projects (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  name text NOT NULL CHECK (char_length(name) > 0),
  description text,
  status text DEFAULT 'active' CHECK (status IN ('active', 'archived', 'deleted')),
  created_at timestamptz DEFAULT now(),
  updated_at timestamptz DEFAULT now()
);

-- 2. Enable RLS (always do this for public tables)
ALTER TABLE public.projects ENABLE ROW LEVEL SECURITY;

-- 3. Create RLS policies
CREATE POLICY "Users can view own projects"
  ON public.projects FOR SELECT TO authenticated
  USING ((SELECT auth.uid()) = user_id);

CREATE POLICY "Users can insert own projects"
  ON public.projects FOR INSERT TO authenticated
  WITH CHECK ((SELECT auth.uid()) = user_id);

CREATE POLICY "Users can update own projects"
  ON public.projects FOR UPDATE TO authenticated
  USING ((SELECT auth.uid()) = user_id)
  WITH CHECK ((SELECT auth.uid()) = user_id);

CREATE POLICY "Users can delete own projects"
  ON public.projects FOR DELETE TO authenticated
  USING ((SELECT auth.uid()) = user_id);

-- 4. Add an index for faster queries
CREATE INDEX idx_projects_user_id ON public.projects (user_id);

-- 5. Create an auto-update trigger for updated_at
CREATE OR REPLACE FUNCTION public.update_updated_at()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$;

CREATE TRIGGER set_updated_at
  BEFORE UPDATE ON public.projects
  FOR EACH ROW
  EXECUTE FUNCTION public.update_updated_at();

-- 6. Query with filters and joins
SELECT
  p.id,
  p.name,
  p.status,
  p.created_at,
  u.email AS owner_email
FROM public.projects p
JOIN auth.users u ON u.id = p.user_id
WHERE p.status = 'active'
ORDER BY p.created_at DESC
LIMIT 50;
```

## Common mistakes

- **Forgetting to enable RLS after creating a table in the SQL Editor** — undefined Fix: 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.
- **Running destructive queries (DROP TABLE, DELETE without WHERE) without a backup** — undefined Fix: 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.
- **Trying to modify the auth schema directly (INSERT INTO auth.users)** — undefined Fix: 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.
- **Writing queries that reference non-existent columns because of a typo** — undefined Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/supabase-tutorial/how-to-write-sql-queries-in-supabase-sql-editor
© RapidDev — https://www.rapidevelopers.com/supabase-tutorial/how-to-write-sql-queries-in-supabase-sql-editor
