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 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.
_10npm i supabase@">=1.8.1" --save-dev
Login with your Personal Access Token:
_10npx supabase login
Generate types for your project to produce the types/supabase.ts
file:
_10npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > types/supabase.ts
These types are generated from your database schema. Given a table public.movies
, the generated types will look like:
_10create table public.movies (_10 id bigint generated always as identity primary key,_10 name text not null,_10 data jsonb null_10);
Using TypeScript type definitions#
You can supply the type definitions to supabase-js
like so:
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:
You can also override the type of an individual successful response if needed:
_10const { data } = await supabase.from('countries').select().returns<MyType>()
Type shorthands#
The generated types provide shorthands for accessing tables and enums.
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:
_10create table countries (_10 "id" serial primary key,_10 "name" text_10);_10_10create table cities (_10 "id" serial primary key,_10 "name" text,_10 "country_id" int references "countries"_10);
We can get the nested CountriesWithCities
type like this:
_15import { QueryResult, QueryData, QueryError } from '@supabase/supabase-js'_15_15const countriesWithCitiesQuery = supabase.from('countries').select(`_15 id,_15 name,_15 cities (_15 id,_15 name_15 )_15`)_15type CountriesWithCities = QueryData<typeof countriesWithCitiesQuery>_15_15const { data, error } = await countriesWithCitiesQuery_15if (error) throw error_15const 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
_10"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.
_39name: Update database types_39_39on:_39 schedule:_39 # sets the action to run daily. You can modify this to run the action more or less frequently_39 - cron: '0 0 * * *'_39_39jobs:_39 update:_39 runs-on: ubuntu-latest_39 env:_39 SUPABASE_ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}_39 PROJECT_REF: <your-project-id>_39 steps:_39 - uses: actions/checkout@v2_39 with:_39 persist-credentials: false_39 fetch-depth: 0_39 - uses: actions/setup-node@v2.1.5_39 with:_39 node-version: 16_39 - run: npm run update-types_39 - name: check for file changes_39 id: git_status_39 run: |_39 echo "status=$(git status -s)" >> $GITHUB_OUTPUT_39 - name: Commit files_39 if: ${{contains(steps.git_status.outputs.status, ' ')}}_39 run: |_39 git add types/database/index.ts_39 git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"_39 git config --local user.name "github-actions[bot]"_39 git commit -m "Update database types" -a_39 - name: Push changes_39 if: ${{contains(steps.git_status.outputs.status, ' ')}}_39 uses: ad-m/github-push-action@master_39 with:_39 github_token: ${{ secrets.GITHUB_TOKEN }}_39 branch: ${{ github.ref }}
Alternatively, you can use a community-supported GitHub action: generate-supabase-db-types-github-action.