Learn about Supabase Database - a full PostgreSQL database with real-time capabilities, row-level security, and powerful extensions.
Every Supabase project comes with a full PostgreSQL database, one of the world’s most stable and advanced relational databases. Supabase extends Postgres with real-time functionality, automatic APIs, and a suite of powerful extensions.
PostgreSQL organizes data into tables within schemas. Supabase creates several schemas by default:
public: Your application tables (exposed via auto-generated APIs)
auth: User authentication data (managed by Supabase Auth)
storage: File metadata (managed by Supabase Storage)
extensions: PostgreSQL extensions
realtime: Real-time configuration
You can create tables using SQL or the Supabase Dashboard:
create table posts ( id bigint generated by default as identity primary key, title text not null, content text, author_id uuid references auth.users(id), created_at timestamp with time zone default timezone('utc'::text, now()) not null);
RLS is PostgreSQL’s built-in authorization system that allows you to control access to individual rows in your tables. Supabase enables RLS by default on new tables.
-- Enable RLSalter table posts enable row level security;-- Create a policy that allows users to read all postscreate policy "Posts are viewable by everyone" on posts for select using (true);-- Create a policy that allows users to insert their own postscreate policy "Users can create their own posts" on posts for insert with check (auth.uid() = author_id);-- Create a policy that allows users to update their own postscreate policy "Users can update their own posts" on posts for update using (auth.uid() = author_id);
Without RLS policies, tables are not accessible via the auto-generated APIs. You must create policies to allow access.
PostgreSQL supports foreign keys to define relationships between tables:
create table comments ( id bigint generated by default as identity primary key, post_id bigint references posts(id) on delete cascade, content text not null, author_id uuid references auth.users(id), created_at timestamp with time zone default now());
The Supabase Dashboard provides a visual interface to explore relationships and navigate between related data.
Indexes improve query performance by allowing the database to find data without scanning every row:
-- Index for faster lookups by authorcreate index posts_author_id_idx on posts(author_id);-- Index for faster sorting by creation datecreate index posts_created_at_idx on posts(created_at desc);-- Composite index for complex queriescreate index comments_post_author_idx on comments(post_id, author_id);
You can create custom functions in PostgreSQL to encapsulate business logic:
create or replace function get_post_count(author uuid)returns bigintlanguage sqlsecurity defineras $$ select count(*) from posts where author_id = author;$$;
Triggers automatically execute functions in response to database events:
-- Function to update a timestampcreate or replace function handle_updated_at()returns triggerlanguage plpgsqlas $$begin new.updated_at = now(); return new;end;$$;-- Trigger that calls the functioncreate trigger set_updated_at before update on posts for each row execute function handle_updated_at();
Use migrations to version control your database schema:
-- supabase/migrations/20240101000000_create_posts.sqlcreate table posts ( id bigint generated by default as identity primary key, title text not null, created_at timestamptz default now());alter table posts enable row level security;