Our @trigger.dev/supabase package provides an integration that wraps the Supabase Management API, allow you to run tasks that can manage your Supabase Orgs, Projects, and Databases.

It also provides the ability to trigger jobs based on changes in your Supabase database through the use of Supabase Database Webhooks.

Usage

There are two different ways to authenticate with the Supabase Management API, either using a Personal Access Token or through OAuth provided by Trigger.dev.

Personal Access Token

To use the Management API integration with a Personal Access Token, head over to your account tokens page and click the “Generate New Token” button. Once you’ve copied the token you should save it to an environment variable in your project, for example SUPABASE_TOKEN and then use it in the SupabaseManagementAPI constructor:

import { SupabaseManagement } from "@trigger.dev/supabase";

const supabaseManagement = new SupabaseManagement({
  id: "supabase-management",
  apiKey: process.env.SUPABASE_TOKEN!,
});

Make sure you have the SUPABASE_TOKEN environment variable set in your project and keep it secret, as it provides full access to your Supabase account.

OAuth

To use the Management API integration with Supabase OAuth, you’ll need to create a new integration in the Trigger.dev dashboard and authorize it with your Supabase account. Once you’ve done that, you can use the SupabaseManagementAPI constructor with the matching id of the integration:

import { SupabaseManagement } from "@trigger.dev/supabase";

const supabaseManagement = new SupabaseManagement({
  id: "supabase-oauth",
});

The access token will automatically be refreshed when it expires, so you don’t need to worry about it, and any job that runs using the integration will have access to your Supabase account.

Jobs & Tasks

Using the SupabaseManagement integration, you can run any of the Management API endpoints as a task inside a job. For example, to create a new Supabase project:

import { TriggerClient, eventTrigger } from "@trigger.dev/sdk"; // this is the Trigger.dev client
import { SupabaseManagement } from "@trigger.dev/supabase";

const client = new TriggerClient({
  apiKey: process.env.TRIGGER_API_KEY!,
});

const supabaseManagement = new SupabaseManagement({
  id: "supabase-management",
});

client.defineJob({
  id: "create-supabase-project",
  name: "Create Supabase Project",
  version: "1.0.0",
  integrations: {
    supabaseManagement,
  },
  trigger: eventTrigger({
    name: "create.project"
  })
  run: async (payload, io, ctx) => {
    await io.supabaseManagement.createProject("🚀", {
      name: payload.name,
      organization_id: payload.organization_id,
      plan: "free",
      region: "us-east-1",
      db_pass: "secret1234"
    })
  }
})

For a full list of available tasks, see the Supabase Management API documentation.

Triggers

The SupabaseManagement integration also provides the ability to trigger jobs based on changes in your Supabase database through the use of Supabase Database Webhooks.

Enable Database Webhooks

Manually enabling database webhooks are only needed if you are using @trigger.dev/supabase at version 2.0.2 or earlier. If you are using 2.0.3 or later, this is done automatically for you.

Currently the Supabase Management API does not provide a way to enable database webhooks, so you’ll need to do this manually.

You can do this by visiting your Database Webhooks settings and clicking the “Enable webhooks” button:

Enable Database Webhooks

You’ll have to do this for each Supabase project you want to use webhooks with.

You don’t actually need to create any webhooks yourself, our integration will take care of that part for you.

Usage

To use this feature, you’ll first initialize a db instance, passing in your Supabase project ID (or URL):

import { SupabaseManagement } from "@trigger.dev/supabase";

const supabaseManagement = new SupabaseManagement({
  id: "supabase-management",
});

const db = supabase.db("https://<your project id>.supabase.co");

Now, you can use the db instance to add a trigger to run a job when a row is inserted, updated, or deleted from a table:

client.defineJob({
  id: "supabase-trigger",
  name: "Supabase Trigger",
  version: "1.0.0",
  trigger: db.onInserted({
    table: "todos",
  }),
  run: async (payload, io, ctx) => {
    // payload is the database webhook body (see https://supabase.com/docs/guides/database/webhooks#payload)
  },
});

You can add additional filters to the trigger by passing a filter object:

client.defineJob({
  id: "supabase-trigger",
  name: "Supabase Trigger",
  version: "1.0.0",
  trigger: db.onUpdated({
    table: "todos",
    // Only trigger if the todo is marked as completed
    filter: {
      old_record: {
        is_completed: [false],
      },
      record: {
        is_completed: [true],
      },
    },
  }),
  run: async (payload, io, ctx) => {
    // payload is the database webhook body (see https://supabase.com/docs/guides/database/webhooks#payload)
  },
});

You can also listen for multiple different events using the on trigger:

client.defineJob({
  id: "supabase-trigger",
  name: "Supabase Trigger",
  version: "1.0.0",
  trigger: db.on({
    table: "todos",
    events: ["INSERT", "UPDATE"] // Trigger on both insert and update events
    filter: {
      record: {
        is_completed: [false],
      },
    },
  }),
  run: async (payload, io, ctx) => {
    if (payload.type === "INSERT") {
      // payload will be typed as the INSERT payload
    } else {
      // payload will be typed as the UPDATE payload
    }
  },
});

We will only create at most 1 database webhook per table, to limit resource usage when writing to your database. This means we cannot support scoping updated triggers to specific columns.

Typescript Support

If you have generated types for your Supabase database, you can use them to get type safety for your database triggers:

import { Database } from "./supabase.types"; // Generated types
import { SupabaseManagement } from "@trigger.dev/supabase";

const supabaseManagement = new SupabaseManagement({
  id: "supabase-management",
});

// Pass the generated types to the db instance
const db = supabase.db<Database>("https://<your project id>.supabase.co");

client.defineJob({
  id: "supabase-trigger",
  name: "Supabase Trigger",
  version: "1.0.0",
  trigger: db.onUpdated({
    table: "todos",
  }),
  run: async (payload, io, ctx) => {
    // payload.record and payload.old_record are now correctly typed to match the todos table
  },
});