Max Rohowsky, Ph.D.

69 views

Supabase Local Development

This post is summary of how to setup a local development environment for Supabase. There's a strong emphasis on the database because that's usually the tricky part. I like to use this post as a cheat sheet for my own reference.

Running Supabase locally

The Supabase command line interface (CLI) lets you to run the entire stack locally. Let's start by creating a new project:

npx supabase init

This creates a supabase folder with a .temp folder and the config.toml file. The former has unimportant stuff, the latter has important configuration stuff.

To start the Supabase stack, you must launch Docker Desktop and run the command below. This takes time the first time because the Docker images need to be downloaded.

npx supabase start

Congrats! You've just created a local development environment for Supabase.

Next, to check the status and get the local development URLs, run:

npx supabase status

To stop the stack, exchange <project_name> with the actual name of your project and run:

npx supabase stop --project-id <project_name>

Using Google auth locally

While testing, it helps to setup Auth to work locally. Here's a quick guide to setup Google Auth on a local Supabase instance. Setting up other Auth providers is similar.

Google Developer Console

Begin by creating new credentials for an OAuth 2.0 client ID in the APIs and services section of the Google Developer Console. Start the setup by clicking on the "Create credentials" button.

Google OAuth 2.0 client ID
Google OAuth 2.0 client ID

During the setup, add the following redirect URI:

http://localhost:54321/auth/v1/callback

That's the standard path for the callback. For testing purposes, the redirect points to your local Supabase instance (see Redirect URI). After walking though the setup, you will get a client ID and client secret (see Client ID and secret):

Redirect URI on Google Developer Console
Redirect URI on Google Developer Console

Supabase configuration

Back in the project, open the config.toml file and add the following to the auth_providers section:

[auth.external.google]
enabled = true
client_id = "env(GOOGLE_CLIENT_ID)"
secret = "env(GOOGLE_CLIENT_SECRET)"
redirect_uri = "http://127.0.0.1:54321/auth/v1/callback"
url = ""
skip_nonce_check = false

Now, create an .env file in the root of the project and add the id and secret you got from the Google Developer Console:

GOOGLE_CLIENT_ID="insert_id_here"
GOOGLE_CLIENT_SECRET="insert_secret_here"

For these changes to take effect, you need to stop and start Supabase. More details on local auth can be found in the Supabase documentation.

NextJS components

The Google auth flow works as follows:

  • User clicks login button which opens Google auth page
  • After successful login user is redirected to Supabase callback: localhost:54321/auth/v1/callback
  • Supabase processes OAuth and redirects to the callback in the NextJS app
  • App callback exchanges code for session and redirects to final destination

Here's an example of a Google login button component that uses the Supabase client to sign-in with Google.

// .../components/google-login.tsx

'use client';

import { FcGoogle } from "react-icons/fc";
import { Button } from "@/components/ui/button";
import { createClient } from "@/utils/supabase/client";
import { AppRoutes } from "@/routes";

export const GoogleLogin = () => {
  const supabase = createClient();

  const onClick = async () => {
    supabase.auth.signInWithOAuth({
      provider: "google",
      options: {
        redirectTo: `${origin}/api/auth/callback?redirect=${encodeURIComponent("/dashboard")}`,
      },
    });
  }

  return (
    <div className="flex items-center w-full gap-x-2">
      <Button
        size="lg"
        className="w-full"
        variant="outline"
        onClick={onClick}
      >
        <FcGoogle className="h-5 w-5" />
      </Button>
    </div>
  )
}

Local database migrations

Migrations let us version control changes — such as creating tables, adding columns, or inserting data — to a database. This ensures that database changes are consistently applied across different environments.

Create a new migration

Migrations are .sql files stored in the supabase/migrations folder. To create a new and empty migration file, run:

npx supabase migration new example_migration

This will create a new file with the name structure <timestamp>_example_migration.sql inside the supabase/migrations folder.

You can add any SQL statements to the migration file, such as:

-- Example migration file

create table if not exists example_table (
    id uuid default gen_random_uuid() primary key,
    message text not null
);

insert into example_table (message) values ('Hello, world!');

This migration file creates the example_table with an id and a message column and inserts a row with data into the table.

Apply a migration locally

By applying a migration, the SQL code in the migration files gets applied to the database on the local Supabase instance. To apply a migration such as the one above, run:

npx supabase migration up

Afterwards, you'll see the changes applied in the Supabase studio?Similar to the dashboard on the Supabase platform but tailored to local development. As you can see from the studio snapshot below, the table and row have been created from the content of the migration file:

Applying a migration
Applying a migration

Pull local schema changes

Pulls schema changes from the local database. A new migration file will be created in the supabase/migrations directory. By default, the the command pulls from the remote database so --local flag is required to pull from the local database.

supabase db pull --local

If the migration history table is empty, pg_dump is used to capture the content of the remote schemas. However, if the migration table has entries, this command will diff schema changes equivalent to npx supabase db diff.

Diff local schema changes

The diff command compares the schema of a target database against a shadow database?The shadow database is created by applying the migration files from your local migrations directory in a separate container generated from the SQL files in your local project's migrations directory.

For convenience, you can add the -f flag to save the schema diff as a new migration file.

npx supabase db diff -f new_changes_migration

Here's an example of a migration file that contains the diff after adding a column to the example_table table (mentioned earlier) in the Supabase studio:

-- Example 'diff'

alter table "public"."example_table" add column "user" text;

It basically created a shadow database from the SQL files in migrations folder from my editor and then compared it to the local database schema. After that, it evaluated the difference and created a new migration file.

Dump the local database

A dump let's us get the schema and data from the database. Here's how to dump the local database schema, data and a specific schema:

npx supabase db dump --local -f supabase/dump_schema.sql

Reset the local database

A reset recreates the local Postgres container and applies all local migrations found in supabase/migrations directory

npx supabase db reset

If test data is defined in supabase/seed.sql, it will be seeded after the migrations are run.

Remote database migrations

The remote database CLI commands are similar to local ones, with a few key differences. For ease of reference, I've dedicated a separate section for the remote database migrations.

Linking to a hosted project

Applying database migrations to the Supabase platform requires a link between your local project and the Supabase platform.

To create the link, insert your project_id (aka. project ref.) into:

npx supabase link --project-ref <project_id>

You'll be prompted for the database password which can be found in Settings / Database.

To remove the link, run:

npx supabase unlink

Apply a remote migration

Applying a migration to a linked remote database is done using:

supabase db push

Once pushed, you can check that the migration version is up to date for the local and remote database by running:

supabase migration list

Pull remote schema changes

Pulls schema changes from a linked remote database. A new migration file will be created under supabase/migrations directory. By default, the the command pulls from the remote database (i.e., --linked flag is optional).

npx supabase db pull

Diff remote schema changes

In contrast to diff'ing against the local database, we need to add the --linked flag to diff against the remote database.

npx supabase db diff -f new_changes_migration --linked

Dump the remote database

The CLI commands are similar to the ones we used for the local database except that we don't use the --local flag:

npx supabase db dump -f supabase/dump_schema.sql

Reset the remote database

To reset the remote database using the migrations in your supabase/migrations folder, include the --linked flag:

npx supabase db reset --linked

Careful with this one. Make a data and schema backup before running this command.

Generating TypeScript Types

To generate TypeScript types for the local or remote database, run:

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

More information on how to use the generated types file can be found in these two blog YouTube videos:

  1. YouTube video.
  2. YouTube video.