Skip to content

Supabase CLI Integration

This guide shows how to integrate Supabase with a React Native (Expo, TypeScript) project using the official todos example.


Install Supabase CLI

Install globally:

brew install supabase/tap/supabase
# or
npm install -g supabase

Check version:

supabase --version

Initialize Supabase Project

supabase init
# or
npx supabase init

This creates a supabase/ folder with:

  • migrations/: This is where your SQL migration files for table and column changes will go.
  • seed.sql: This is where you can put SQL commands to seed initial data into your database.
  • config.toml: This is the configuration file for your Supabase project.

Start Local Supabase (Docker)

Pre-requisite: Docker installed.

supabase start

This runs PostgreSQL, Studio, Auth, Realtime, and Storage locally by using Docker.

Check Supabase Status

You can inspect the local services with:

supabase status

This shows useful connection details:

  • API URL → REST API base endpoint for client requests
  • GraphQL URL → GraphQL endpoint
  • S3 Storage URL → Storage service endpoint
  • Database URL → PostgreSQL connection string (use in psql/clients)
  • Studio URL → Local Supabase Studio (browser UI)
  • Mailpit URL → Local email testing server (see passwordless links)
  • Publishable key → Public (client-side) key for local dev (not a real JWT)
  • Secret key → Private (server-side) key for admin operations
  • S3 Access Key / Secret Key → Credentials for accessing storage
  • S3 Region → Dummy region for local S3 storage

Stop Local Database

To stop:

supabase stop

Stop the local Supabase Docker containers without taking a backup:

supabase stop --no-backup
  • Use this if you want to cleanly shut down local services.
  • The --no-backup flag prevents creating a dump before stopping.

Database Setup & RLS Policies


Environment Variables (Expo)

Create a .env file in your project:

  • local (.env.local):
EXPO_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
EXPO_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...

Local Supabase keys are not valid JWTs. You can get anon key from local dashboard under Settings → API by using Studio URL.

  • prod (.env.production):
EXPO_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...

Restart Expo:

npx expo start -c

Supabase Client (TypeScript)

Install Supabase SDK

npm install @supabase/supabase-js

Setup Supabase Client

utils/supabase.ts:

import {createClient} from '@supabase/supabase-js';

export type Todo = {
    id: number;
    title: string;
    is_complete: boolean;
    inserted_at: string;
};

export type Database = {
    public: {
        Tables: {
            todos: {
                Row: Todo;
                Insert: Omit<Todo, 'id' | 'inserted_at'>;
                Update: Partial<Omit<Todo, 'id'>>;
            };
        };
    };
};

const SUPABASE_URL = process.env.EXPO_PUBLIC_SUPABASE_URL as string;
const SUPABASE_ANON_KEY = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY as string;

if (!SUPABASE_URL || !SUPABASE_ANON_KEY) {
    throw new Error('Missing Supabase environment variables');
}

export const supabase = createClient<Database>(
    SUPABASE_URL,
    SUPABASE_ANON_KEY
);

React Native Example (Todos Screen)

todos.tsx:

import React, {useState, useEffect} from 'react';
import {View, Text, FlatList, ActivityIndicator} from 'react-native';
import {supabase} from './utils/supabase';
import type {Todo} from './utils/supabase';

export default function TodosScreen() {
    const [todos, setTodos] = useState<Todo[]>([]);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        const getTodos = async () => {
            setLoading(true);
            const {data, error} = await supabase.from('todos').select('*');
            if (error) {
                console.error('Error fetching todos:', error.message);
            } else if (data) {
                setTodos(data);
            }
            setLoading(false);
        };

        getTodos();
    }, []);

    if (loading) {
        return (
            <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
                <ActivityIndicator size="large" color="#2563eb"/>
            </View>
        );
    }

    return (
        <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
            <Text style={{fontWeight: 'bold', fontSize: 20}}>Todo List</Text>
            <FlatList
                data={todos}
                keyExtractor={(item) => item.id.toString()}
                renderItem={({item}) => (
                    <Text>
                        {item.title} {item.is_complete ? '✅' : '⬜️'}
                    </Text>
                )}
            />
        </View>
    );
}

Cloud Project Setup (Prod)

For your production environment, you need a Supabase Cloud project:

  1. Go to Supabase Dashboard
  2. Create a project
  3. Copy your API URL and anon key from Settings → API

Authentication for CLI

Before linking, log in with your personal access token (one-time setup):

supabase login

This will open a browser where you can get your access token from the dashboard (Account Settings → Access Tokens).

Linking Local Project to Cloud

Link your local Supabase project folder to a specific cloud project:

supabase link --project-ref your-project-ref

your-project-ref is the unique identifier for your Supabase cloud project (found in project settings).

Push Local Migrations to Cloud

Once linked, you can push your local migrations to the cloud database:

supabase db push

If you want to disconnect your local project from the cloud:

supabase unlink

✅ Summary:

  • supabase login → authenticate CLI with your Supabase account.
  • supabase link → connect local project to a specific cloud project.
  • supabase db push → apply local migrations to the cloud database.
  • supabase unlink → remove the link between local and cloud projects.

CI/CD Deployment

In a CI/CD pipeline (e.g., GitHub Actions, GitLab CI, Vercel, etc.), you can automate pushing migrations and deploying functions.

Generate a Personal Access Token

In the Supabase Dashboard → Account Settings → Access Tokens, create a new token.
Store this securely in your CI/CD provider as a secret environment variable:

SUPABASE_ACCESS_TOKEN=your-token

Example GitHub Actions Workflow

Create .github/workflows/deploy.yml:

name: Deploy Supabase

on:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: supabase/setup-cli@v1
        with:
          version: latest
      - run: supabase link --project-ref $SUPABASE_PROJECT_REF
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
      - run: supabase db push
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

✅ With this setup:

  • Every push to master will link your project.
  • Apply new migrations automatically on the cloud database.
  • No need to run supabase login manually in CI/CD; the access token handles authentication.

Database Sync (Cloud ↔ Local)

Sometimes you need to synchronize your local database with the cloud (production) database for testing or development.

Pull Cloud Schema to Local

Fetch the current cloud database schema and create a migration file:

supabase db pull
  • Creates a SQL file under supabase/migrations/ with the full schema.
  • Use this when local DB is empty, or you want to match cloud schema.

Note: This only pulls the schema, not the data.

Generate Migration from Differences

Compare your local DB with the cloud DB and create a migration for the differences:

supabase db diff -f add_new_table
  • Generates a migration file in supabase/migrations/.
  • Useful when you made changes locally and want to push them to the cloud.

Pull Cloud Data (Optional)

If you want existing cloud data locally for testing:

supabase db dump --data-only > supabase/seed.sql

Then reset local DB and load the data:

supabase db reset
psql "postgresql://postgres:postgres@127.0.0.1:54322/postgres" -f supabase/seed.sql

This will give you a local copy of cloud data for development/testing purposes.


✅ Summary:

  • db pull → Pull cloud schema only
  • db diff → Generate migration from local vs cloud differences
  • db dump --data-only → Pull cloud data

Common CLI Commands

supabase init                     # initialize project
supabase start                    # start local containers
supabase stop                     # stop local containers
supabase db reset                 # reset DB and reapply migrations
supabase db diff -f <name>        # create migration from schema changes
supabase link --project-ref <ID>  # link local project to cloud
supabase db push                  # push migrations to cloud

  • Use Cloud Supabase for the app → for Auth, Realtime, RLS, and proper anon keys.
  • Use Local Docker Supabase for DB dev → for schema changes, migrations, seeds.
  • Deploy to production via supabase db push in CI/CD.

References