Files
James Ritchie fade22015f Docs – v4 GA updates (#2298)
* Adds new features table to top of v4 upgrade guide

* Adds wait idempotency to wait-until, wait-for, and wait-for-token pages

* Adds new priority docs page and updates the v4 upgrade guide

* Adds new task lifecycle hooks

* Removes the message about requiring tasks to be exported

* Adds new global lifecycle hooks section

* Moves sections from upgrade guide into the table

* Adds hidden task page

* Improves the global lifecycle hooks section

* Updates middleware and locals section

* Adds new useWaitToken page to the react hooks section

* Adds a new ai.tool section

* Moves Docker (legacy) page into self-hosting section

* Removes known issues from v4 upgrade guide

* Replace “toolTask” with “ai.tool” in the Streams page example

* Renames guide to “Migrating from v3” and adds redirect

* Remove references to v4

* Removes changelog from migration guide

* The installation guide now references `@latest update`

* Changes all references from `/sdk/v3` to `/sdk`

* Updates @v4-beta to @latest

* Fixed broken link

* Fixes broken link

* Adds an upgrade to v4 using AI section

* Fixes 2 broken links

* Adds an entry for targetting preview branches

* Updates the run statuses

* Adds boolean helpers section to the runs and realtime pages

* Updates the concurrency page

* Updates the test page to include the new options

* Adds SDK and curl options for the preview branch targeting

* Updates new bulk actions page

* Remove the releasing concurrency section

* Got rid of some more @v4-beta mentions

* Improved rate limit docs

* Improved migrating docs

* Removed commented sections of the docs

* useWaitToken hook

* Fixed the description

* Fix for missing test image

---------

Co-authored-by: Matt Aitken <matt@mattaitken.com>
Co-authored-by: Dan <8297864+D-K-P@users.noreply.github.com>
2025-08-18 12:34:55 +01:00

209 lines
7.5 KiB
Plaintext

---
title: "Supabase database operations using Trigger.dev"
sidebarTitle: "Supabase database operations"
description: "These examples demonstrate how to run basic CRUD operations on a table in a Supabase database using Trigger.dev."
---
import SupabaseDocsCards from "/snippets/supabase-docs-cards.mdx";
import SupabaseAuthInfo from "/snippets/supabase-auth-info.mdx";
## Add a new user to a table in a Supabase database
This is a basic task which inserts a new row into a table from a Trigger.dev task.
### Key features
- Shows how to set up a Supabase client using the `@supabase/supabase-js` library
- Shows how to add a new row to a table using `insert`
### Prerequisites
- A [Supabase account](https://supabase.com/dashboard/) and a project set up
- In your Supabase project, create a table called `user_subscriptions`.
- In your `user_subscriptions` table, create a new column:
- `user_id`, with the data type: `text`
### Task code
```ts trigger/supabase-database-insert.ts
import { createClient } from "@supabase/supabase-js";
import { task } from "@trigger.dev/sdk";
import jwt from "jsonwebtoken";
// Generate the Typescript types using the Supabase CLI: https://supabase.com/docs/guides/api/rest/generating-types
import { Database } from "database.types";
export const supabaseDatabaseInsert = task({
id: "add-new-user",
run: async (payload: { userId: string }) => {
const { userId } = payload;
// Get JWT secret from env vars
const jwtSecret = process.env.SUPABASE_JWT_SECRET;
if (!jwtSecret) {
throw new Error("SUPABASE_JWT_SECRET is not defined in environment variables");
}
// Create JWT token for the user
const token = jwt.sign({ sub: userId }, jwtSecret, { expiresIn: "1h" });
// Initialize Supabase client with JWT
const supabase = createClient<Database>(
process.env.SUPABASE_URL as string,
process.env.SUPABASE_ANON_KEY as string,
{
global: {
headers: {
Authorization: `Bearer ${token}`,
},
},
}
);
// Insert a new row into the user_subscriptions table with the provided userId
const { error } = await supabase.from("user_subscriptions").insert({
user_id: userId,
});
// If there was an error inserting the new user, throw an error
if (error) {
throw new Error(`Failed to insert new user: ${error.message}`);
}
return {
message: `New user added successfully: ${userId}`,
};
},
});
```
<SupabaseAuthInfo />
### Testing your task
To test this task in the [Trigger.dev dashboard](https://cloud.trigger.dev), you can use the following payload:
```json
{
"userId": "user_12345"
}
```
If the task completes successfully, you will see a new row in your `user_subscriptions` table with the `user_id` set to `user_12345`.
## Update a user's subscription on a table in a Supabase database
This task shows how to update a user's subscription on a table. It checks if the user already has a subscription and either inserts a new row or updates an existing row with the new plan.
This type of task is useful for managing user subscriptions, updating user details, or performing other operations you might need to do on a database table.
### Key features
- Shows how to set up a Supabase client using the `@supabase/supabase-js` library
- Adds a new row to the table if the user doesn't exist using `insert`
- Checks if the user already has a plan, and if they do updates the existing row using `update`
- Demonstrates how to use [AbortTaskRunError](https://trigger.dev/docs/errors-retrying#using-aborttaskrunerror) to stop the task run without retrying if an invalid plan type is provided
### Prerequisites
- A [Supabase account](https://supabase.com/dashboard/) and a project set up
- In your Supabase project, create a table called `user_subscriptions` (if you haven't already)
- In your `user_subscriptions` table, create these columns (if they don't already exist):
- `user_id`, with the data type: `text`
- `plan`, with the data type: `text`
- `updated_at`, with the data type: `timestamptz`
### Task code
```ts trigger/supabase-update-user-subscription.ts
import { createClient } from "@supabase/supabase-js";
import { AbortTaskRunError, task } from "@trigger.dev/sdk";
// Generate the Typescript types using the Supabase CLI: https://supabase.com/docs/guides/api/rest/generating-types
import { Database } from "database.types";
// Define the allowed plan types
type PlanType = "hobby" | "pro" | "enterprise";
// Create a single Supabase client for interacting with your database
// 'Database' supplies the type definitions to supabase-js
const supabase = createClient<Database>(
// These details can be found in your Supabase project settings under `API`
process.env.SUPABASE_PROJECT_URL as string, // e.g. https://abc123.supabase.co - replace 'abc123' with your project ID
process.env.SUPABASE_SERVICE_ROLE_KEY as string // Your service role secret key
);
export const supabaseUpdateUserSubscription = task({
id: "update-user-subscription",
run: async (payload: { userId: string; newPlan: PlanType }) => {
const { userId, newPlan } = payload;
// Abort the task run without retrying if the new plan type is invalid
if (!["hobby", "pro", "enterprise"].includes(newPlan)) {
throw new AbortTaskRunError(
`Invalid plan type: ${newPlan}. Allowed types are 'hobby', 'pro', or 'enterprise'.`
);
}
// Query the user_subscriptions table to check if the user already has a subscription
const { data: existingSubscriptions } = await supabase
.from("user_subscriptions")
.select("user_id")
.eq("user_id", userId);
if (!existingSubscriptions || existingSubscriptions.length === 0) {
// If there are no existing users with the provided userId and plan, insert a new row
const { error: insertError } = await supabase.from("user_subscriptions").insert({
user_id: userId,
plan: newPlan,
updated_at: new Date().toISOString(),
});
// If there was an error inserting the new subscription, throw an error
if (insertError) {
throw new Error(`Failed to insert user subscription: ${insertError.message}`);
}
} else {
// If the user already has a subscription, update their existing row
const { error: updateError } = await supabase
.from("user_subscriptions")
// Set the plan to the new plan and update the timestamp
.update({ plan: newPlan, updated_at: new Date().toISOString() })
.eq("user_id", userId);
// If there was an error updating the subscription, throw an error
if (updateError) {
throw new Error(`Failed to update user subscription: ${updateError.message}`);
}
}
// Return an object with the userId and newPlan
return {
userId,
newPlan,
};
},
});
```
<Note>
This task uses your service role secret key to bypass Row Level Security. There are different ways
of configuring your [RLS
policies](https://supabase.com/docs/guides/database/postgres/row-level-security), so always make
sure you have the correct permissions set up for your project.
</Note>
### Testing your task
To test this task in the [Trigger.dev dashboard](https://cloud.trigger.dev), you can use the following payload:
```json
{
"userId": "user_12345",
"newPlan": "pro"
}
```
If the task completes successfully, you will see a new row in your `user_subscriptions` table with the `user_id` set to `user_12345`, the `plan` set to `pro`, and the `updated_at` timestamp updated to the current time.
<SupabaseDocsCards />