REST API

Generating TypeScript Types

How to generate types for your API and Supabase libraries.

Supabase APIs are generated from your database, which means that we can use database introspection to generate type-safe API definitions.

Generating types from project dashboard

Supabase allows you to generate and download TypeScript types directly from the project dashboard.

Generating types using Supabase CLI

The Supabase CLI is a single binary Go application that provides everything you need to setup a local development environment.

You can install the CLI via npm or other supported package managers. The minimum required version of the CLI is v1.8.1.

npm i supabase@">=1.8.1" --save-dev

Login with your Personal Access Token:

npx supabase login

Before generating types, ensure you initialize your Supabase project:

npx supabase init

Generate types for your project to produce the types/supabase.ts file:

npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > types/supabase.ts

or in case of local development:

npx supabase gen types typescript --local > types/supabase.ts

These types are generated from your database schema. Given a table public.movies, the generated types will look like:

create table public.movies (
id bigint generated always as identity primary key,
name text not null,
data jsonb null
);
./database.types.ts
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]

export interface Database {
public: {
Tables: {
movies: {
Row: {
// the data expected from .select()
id: number
name: string
data: Json | null
}
Insert: {
// the data to be passed to .insert()
id?: never // generated columns must not be supplied
name: string // `not null` columns with no default must be supplied
data?: Json | null // nullable columns can be omitted
}
Update: {
// the data to be passed to .update()
id?: never
name?: string // `not null` columns are optional on .update()
data?: Json | null
}
}
}
}
}

Using TypeScript type definitions

You can supply the type definitions to supabase-js like so:

./index.tsx
import { createClient } from '@supabase/supabase-js'
import { Database } from './database.types'

const supabase = createClient<Database>(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY)

Helper types for tables and joins

You can use the following helper types to make the generated TypeScript types easier to use.

Sometimes the generated types are not what you expect. For example, a view's column may show up as nullable when you expect it to be not null. Using type-fest, you can override the types like so:

./database-generated.types.ts
export type Json = // ...

export interface Database {
// ...
}
./database.types.ts
import { MergeDeep } from 'type-fest'
import { Database as DatabaseGenerated } from './database-generated.types'
export { Json } from './database-generated.types'

// Override the type for a specific column in a view:
export type Database = MergeDeep<
DatabaseGenerated,
{
public: {
Views: {
movies_view: {
Row: {
// id is a primary key in public.movies, so it must be `not null`
id: number
}
}
}
}
}
>

You can also override the type of an individual successful response if needed:

const { data } = await supabase.from('countries').select().returns<MyType>()

Type shorthands

The generated types provide shorthands for accessing tables and enums.

./index.ts
import { Database, Tables, Enums } from "./database.types.ts";

// Before 😕
let movie: Database['public']['Tables']['movies']['Row'] = // ...

// After 😍
let movie: Tables<'movies'>

Response types for complex queries

supabase-js always returns a data object (for success), and an error object (for unsuccessful requests).

These helper types provide the result types from any query, including nested types for database joins.

Given the following schema with a relation between cities and countries:

create table countries (
"id" serial primary key,
"name" text
);

create table cities (
"id" serial primary key,
"name" text,
"country_id" int references "countries"
);

We can get the nested CountriesWithCities type like this:

import { QueryResult, QueryData, QueryError } from '@supabase/supabase-js'

const countriesWithCitiesQuery = supabase.from('countries').select(`
id,
name,
cities (
id,
name
)
`)
type CountriesWithCities = QueryData<typeof countriesWithCitiesQuery>

const { data, error } = await countriesWithCitiesQuery
if (error) throw error
const countriesWithCities: CountriesWithCities = data

Update types automatically with GitHub Actions

One way to keep your type definitions in sync with your database is to set up a GitHub action that runs on a schedule.

Add the script above to your package.json to run it using npm run update-types

"update-types": "npx supabase gen types typescript --project-id \"$PROJECT_REF\" > types/supabase.ts"

Create a file .github/workflows/update-types.yml with the following snippet to define the action along with the environment variables. This script will commit new type changes to your repo every night.

name: Update database types

on:
schedule:
# sets the action to run daily. You can modify this to run the action more or less frequently
- cron: '0 0 * * *'

jobs:
update:
runs-on: ubuntu-latest
permissions:
contents: write
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
PROJECT_REF: <your-project-id>
steps:
- uses: actions/checkout@v2
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@v2.1.5
with:
node-version: 16
- run: npm run update-types
- name: check for file changes
id: git_status
run: |
echo "status=$(git status -s)" >> $GITHUB_OUTPUT
- name: Commit files
if: ${{contains(steps.git_status.outputs.status, ' ')}}
run: |
git add types/supabase.ts
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit -m "Update database types" -a
- name: Push changes
if: ${{contains(steps.git_status.outputs.status, ' ')}}
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}

Alternatively, you can use a community-supported GitHub action: generate-supabase-db-types-github-action.

Resources

We only collect analytics essential to ensuring smooth operation of our services. Learn more