Serverless APIs

Supabase auto-generates three types of API directly from your database schema.

  • REST - interact with your database through a restful interface.
  • Realtime - listen to database changes.
  • GraphQL - in beta.

The APIs are:

  • Instant and auto-generated.
    As you update your database the changes are immediately accessible through your API.
  • Self documenting.
    Supabase generates documentation in the Dashboard which updates as you make database changes.
  • Secure.
    The API is configured to work with PostgreSQL's Row Level Security, provisioned behind an API gateway with key-auth enabled.
  • Fast.
    Our benchmarks for basic reads are more than 300% faster than Firebase. The API is a very thin layer on top of Postgres, which does most of the heavy lifting.
  • Scalable.
    The API can serve thousands of simultaneous requests, and works well for Serverless workloads.


Supabase provides a RESTful API using PostgREST. This is a very thin API layer on top of Postgres. It provides everything you need from a CRUD API:

  • Basic CRUD operations
  • Deeply nested joins, allowing you to fetch data from multiple tables in a single fetch
  • Works with Postgres Views
  • Works with Postgres Functions
  • Works with the Postgres security model - including Row Level Security, Roles, and Grants.

GraphQL API #


GraphQL is in Beta, and may have breaking changes. It is only available on self-hosted setups and Supabase projects created after 28th March 2022.

GraphQL in Supabase works through pg_graphql, an open source PostgreSQL extension for GraphQL.

Realtime API #

Supabase provides a Realtime API using Realtime. You can use this to listen to database changes over websockets. Realtime leverages PostgreSQL's built-in logical replication. You can manage your Realtime API simply by managing Postgres publications. Go to your project's Replication section to get started.

Getting started#

All APIs are auto-created from Database tables. After you have added tables or functions to your database, you can use the APIs provided.

Creating API Routes#

API routes are automatically created when you create Postgres Tables, Views, or Functions.

Let's create our first API route by creating a table called todos to store tasks. This creates a corresponding route todos which can accept GET, POST, PATCH, & DELETE requests.

  1. Go to the Table editor page in the Dashboard.
  2. Click New Table and create a table with the name todos.
  3. Click Save.
  4. Click New Column and create a column with the name task and type text.
  5. Click Save.

API URL and Keys#

Every Supabase project has a unique API URL. Your API is secured behind an API gateway which requires an API Key for every request.

  1. Go to the Settings page in the Dashboard.
  2. Click API in the sidebar.
  3. Find your API URL, anon, and service_role keys on this page.

The REST API and the GraphQL API are both accessible through this URL:

  • REST: https://<project_ref>.supabase.co/rest/v1
  • GraphQL: https://<project_ref>.supabase.co/graphql/v1

Both of these routes require the anon key to be passed through an apikey header.

API Keys

You are provided with two keys:

  • an anon key, which is safe to be used in a browser context.
  • a service_role key, which should only be used on a server. This key can bypass Row Level Security. NEVER use this key in a browser.

Accessing the docs in the Dashboard#

REST API [#rest-api-dashboard-docs]

Supabase generates documentation in the Dashboard which updates as you make database changes. Let's view the documentation for a countries table which we created in our database.

  1. Go to the API page in the Dashboard.
  2. Find the countries table under Tables and Views in the sidebar.
  3. Switch between the JavaScript and the cURL docs using the tabs.


The GraphQL Endpoint that we provide (https://<project_ref>.supabase.co/graphql/v1) is compatible with any GraphiQL implementation that can pass an apikey header. Some suggested applications:

Using the API#


You can interact with your API directly via HTTP requests, or you can use the client libraries which we provide.

Let's see how to make a request to the todos table which we created in the first step, using the API URL (SUPABASE_URL) and Key (SUPABASE_ANON_KEY) we provided:

// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

// Make a request
const { data: todos, error } = await supabase.from('todos').select('*')

JS Reference: select(), insert(), update(), upsert(), delete(), rpc() (call Postgres functions).

GraphQL API#

You can use any GraphQL client with the Supabase GraphQL API. For our GraphQL example we will use urql.

import { createClient, useQuery } from 'urql'

// Prepare API key and Authorization header
const headers = {
  apikey: <SUPABASE_ANON_KEY>,
  authorization: `Bearer ${<SUPABASE_ANON_KEY>}`,

// Create GraphQL client
// See: https://formidable.com/open-source/urql/docs/basics/react-preact/#setting-up-the-client
const client = createClient({
  url: '<SUPABASE_URL>/graphql/v1',
  fetchOptions: function createFetchOptions() {
    return { headers }

// Prepare our GraphQL query
const TodosQuery = `
  query {
    todosCollection {
      edges {
        node {

// Query for the data (React)
const [result, reexecuteQuery] = useQuery({
  query: TodosQuery,

// Read the result
const { data, fetching, error } = result

Realtime API#

By default Realtime is disabled on your database. Let's turn on Realtime for the todos table.

  1. Go to the Database page in the Dashboard.
  2. Click on Replication in the sidebar.
  3. Control which database events are sent by toggling Insert, Update, and Delete.
  4. Control which tables broadcast changes by selecting Source and toggling each table.

From the client, we can listen to any new data that is inserted into the todos table:

// Initialize the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

// Create a function to handle inserts
const handleInserts = (payload) => {
  console.log('Change received!', payload)

// Listen to inserts
const { data: todos, error } = await supabase.from('todos').on('INSERT', handleInserts).subscribe()

Use subscribe() to listen to database changes. The Realtime API works through PostgreSQL's replication functionality. Postgres sends database changes to a publication called supabase_realtime, and by managing this publication you can control which data is broadcast.

API Security#

Securing your Routes#

Your API is designed to work with Postgres Row Level Security (RLS). If you use Supabase Auth, you can restrict data based on the logged-in user. To control access to your data, you can use Policies. When you create a table in Postgres, Row Level Security is disabled by default. To enable RLS:

  1. Go to the Authentication page in the Dashboard.
  2. Click on Policies in the sidebar.
  3. Select Enable RLS to enable Row Level Security.

The service_role key#

Never expose the service_role key in a browser or anywhere where a user can see it. This Key is designed to bypass Row Level Security - so it should only be used on a private server.

A common use case for the service_role key is to run data analytics jobs on the backend. To support joins on user id, it is often useful to grant the service role read access to auth.users table.

grant select on table auth.users to service_role;

We have partnered with GitHub to scan for Supabase service_role keys pushed to public repositories. If they detect any keys with service_role privileges being pushed to GitHub, they will forward the API key to us, so that we can automatically revoke the detected secrets and notify you, protecting your data against malicious actors.

Safeguards towards accidental deletes and updates#

For all projects, by default, the Postgres extension safeupdate is enabled for all queries coming from the API. This ensures that any delete() or update() would fail if there are no accompanying filters provided. To confirm that safeupdate is enabled for queries going through the API of your project, the following query could be run:

select usename, useconfig from pg_shadow where usename = 'authenticator';

The expected value for useconfig should be:

['session_preload_libraries=supautils, safeupdate']
Need some help?

Not to worry, our specialist engineers are here to help. Submit a support ticket through the Dashboard.