Skip to content

Commit 057b898

Browse files
committed
self-hosted supabase guidde
1 parent c5f45ae commit 057b898

File tree

5 files changed

+236
-98
lines changed

5 files changed

+236
-98
lines changed

pkgs/website/src/content/docs/deploy/database-connection.mdx

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,46 @@ sidebar:
55
order: 110
66
---
77

8-
import { Aside, CardGrid, LinkCard } from "@astrojs/starlight/components";
8+
import { Aside, CardGrid, LinkCard } from '@astrojs/starlight/components';
99

1010
pgflow auto-detects your database connection in local development and requires minimal configuration for production. This guide explains how connection detection works and how to configure it for different environments.
1111

1212
## Connection Priority
1313

1414
When an Edge Worker starts, pgflow resolves the database connection using this priority chain:
1515

16-
| Priority | Source | Use Case |
17-
|----------|--------|----------|
18-
| 1 | `config.sql` | Full postgres.js control (SSL, custom options) |
19-
| 2 | `config.connectionString` | Custom connection URL |
20-
| 3 | `EDGE_WORKER_DB_URL` | Production environment variable |
21-
| 4 | Local fallback | Supabase local development (automatic) |
16+
| Priority | Source | Use Case |
17+
| -------- | ------------------------- | ---------------------------------------------- |
18+
| 1 | `config.sql` | Full postgres.js control (SSL, custom options) |
19+
| 2 | `config.connectionString` | Custom connection URL |
20+
| 3 | `EDGE_WORKER_DB_URL` | Production environment variable |
21+
| 4 | Local fallback | Supabase local development (automatic) |
2222

2323
If none of these are available, the worker throws an error: `"No database connection available"`.
2424

2525
<Aside type="note" title="Explicit config wins">
26-
Providing `config.sql`, `config.connectionString`, or `EDGE_WORKER_DB_URL` **skips the automatic local connection**. The local fallback only applies when no explicit configuration is provided.
26+
Providing `config.sql`, `config.connectionString`, or `EDGE_WORKER_DB_URL`
27+
**skips the automatic local connection**. The local fallback only applies when
28+
no explicit configuration is provided.
2729
</Aside>
2830

2931
## Local Development
3032

3133
When running locally with `supabase start`, pgflow automatically connects to your database without any configuration needed.
3234

3335
```typescript title="supabase/functions/my-worker/index.ts"
34-
import { EdgeWorker } from "@pgflow/edge-worker";
35-
import { MyFlow } from "../../flows/index.ts";
36+
import { EdgeWorker } from '@pgflow/edge-worker';
37+
import { MyFlow } from '../../flows/index.ts';
3638

3739
// Just works locally - no config needed!
3840
EdgeWorker.start(MyFlow);
3941
```
4042

4143
<Aside type="note" title="How local connections work">
42-
pgflow recognizes local Supabase environments by checking for known local dev credentials in environment variables. When running locally, it connects to the Docker pooler at `postgresql://postgres.localhost:postgres@127.0.0.1:54329/postgres`.
44+
pgflow recognizes local Supabase environments by checking for known local dev
45+
credentials in environment variables. When running locally, it connects to the
46+
Docker pooler at
47+
`postgresql://postgres.localhost:postgres@127.0.0.1:54329/postgres`.
4348
</Aside>
4449

4550
## Production Deployment
@@ -50,11 +55,18 @@ For production, set the `EDGE_WORKER_DB_URL` secret in your Supabase project:
5055
npx supabase secrets set EDGE_WORKER_DB_URL="postgresql://postgres.pooler-yourproject:[YOUR-PASSWORD]@aws-0-us-east-1.pooler.supabase.com:6543/postgres"
5156
```
5257

58+
<Aside type="note" title="Self-hosted Supabase">
59+
Self-hosted instances do not auto-configure `EDGE_WORKER_DB_URL`. You must set
60+
it explicitly in your Edge Function environment. See the [Self-Hosted Supabase
61+
guide](/deploy/supabase/self-hosted/) for the connection string format for
62+
your pooler.
63+
</Aside>
64+
5365
Your worker code stays the same - pgflow automatically uses the environment variable when not in local development:
5466

5567
```typescript title="supabase/functions/my-worker/index.ts"
56-
import { EdgeWorker } from "@pgflow/edge-worker";
57-
import { MyFlow } from "../../flows/index.ts";
68+
import { EdgeWorker } from '@pgflow/edge-worker';
69+
import { MyFlow } from '../../flows/index.ts';
5870

5971
// Uses EDGE_WORKER_DB_URL in production
6072
EdgeWorker.start(MyFlow);
@@ -69,11 +81,11 @@ See [Get Connection String](/deploy/supabase/get-connection-string/) for how to
6981
If you need to use a custom connection URL (different from `EDGE_WORKER_DB_URL`), pass it via `config.connectionString`:
7082

7183
```typescript title="supabase/functions/my-worker/index.ts"
72-
import { EdgeWorker } from "@pgflow/edge-worker";
73-
import { MyFlow } from "../../flows/index.ts";
84+
import { EdgeWorker } from '@pgflow/edge-worker';
85+
import { MyFlow } from '../../flows/index.ts';
7486

7587
EdgeWorker.start(MyFlow, {
76-
connectionString: Deno.env.get("MY_CUSTOM_DB_URL"),
88+
connectionString: Deno.env.get('MY_CUSTOM_DB_URL'),
7789
});
7890
```
7991

@@ -82,14 +94,14 @@ EdgeWorker.start(MyFlow, {
8294
For advanced scenarios requiring SSL certificates or other postgres.js settings, create the SQL client yourself and pass it via `config.sql`. Note that `prepare: false` is required when using a transaction pooler:
8395

8496
```typescript title="supabase/functions/my-worker/index.ts" {6}
85-
import { EdgeWorker } from "@pgflow/edge-worker";
86-
import postgres from "postgres";
87-
import { MyFlow } from "../../flows/index.ts";
97+
import { EdgeWorker } from '@pgflow/edge-worker';
98+
import postgres from 'postgres';
99+
import { MyFlow } from '../../flows/index.ts';
88100

89-
const sql = postgres(Deno.env.get("DATABASE_URL")!, {
101+
const sql = postgres(Deno.env.get('DATABASE_URL')!, {
90102
prepare: false, // Required for transaction pooling
91103
connection: {
92-
application_name: "my-flow-worker", // Visible in pg_stat_activity
104+
application_name: 'my-flow-worker', // Visible in pg_stat_activity
93105
},
94106
});
95107

@@ -103,12 +115,12 @@ See [Database SSL](/deploy/database-ssl/) for SSL configuration examples.
103115
If you need to connect to a different database during local development (e.g., a remote staging database), provide an explicit configuration:
104116

105117
```typescript title="supabase/functions/my-worker/index.ts"
106-
import { EdgeWorker } from "@pgflow/edge-worker";
107-
import { MyFlow } from "../../flows/index.ts";
118+
import { EdgeWorker } from '@pgflow/edge-worker';
119+
import { MyFlow } from '../../flows/index.ts';
108120

109121
// Skips automatic local connection, uses custom URL instead
110122
EdgeWorker.start(MyFlow, {
111-
connectionString: Deno.env.get("STAGING_DB_URL"),
123+
connectionString: Deno.env.get('STAGING_DB_URL'),
112124
});
113125
```
114126

pkgs/website/src/content/docs/deploy/index.mdx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ Learn how to deploy pgflow to production, monitor workflow execution, and mainta
1111

1212
<CardGrid>
1313
<LinkCard
14-
title="Deploy to Supabase"
14+
title="Supabase.com"
1515
href="/deploy/supabase/"
1616
description="Step-by-step guide to deploying pgflow workers to Supabase.com production"
1717
/>
18+
<LinkCard
19+
title="Self-Hosted Supabase"
20+
href="/deploy/supabase/self-hosted/"
21+
description="Deploy pgflow on self-hosted Supabase instances running on your own infrastructure"
22+
/>
1823
</CardGrid>
1924

2025
## Configure

pkgs/website/src/content/docs/deploy/supabase/index.mdx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,25 @@ sidebar:
55
order: 0
66
---
77

8-
import { Steps, LinkButton, Card, CardGrid, LinkCard } from "@astrojs/starlight/components";
8+
import {
9+
Steps,
10+
LinkButton,
11+
Card,
12+
CardGrid,
13+
LinkCard,
14+
Aside,
15+
} from '@astrojs/starlight/components';
916

1017
This guide walks you through deploying pgflow workers to Supabase.com. Workers run as Edge Functions that poll for tasks, execute your flow handlers, and report results back to the database.
1118

1219
Before starting, ensure you have completed [Getting Started](/get-started/installation/) and have a Supabase project linked to your local environment.
1320

21+
<Aside type="tip" title="Self-hosted Supabase?">
22+
Running Supabase on your own infrastructure? See the [Self-Hosted Supabase
23+
guide](/deploy/supabase/self-hosted/) for specific setup instructions
24+
including Postgres image upgrades and database connection configuration.
25+
</Aside>
26+
1427
## Deployment Overview
1528

1629
<Steps>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
title: Self-Hosted Supabase
3+
description: Deploy pgflow on self-hosted Supabase instances running on your own infrastructure
4+
sidebar:
5+
order: 50
6+
---
7+
8+
import { Aside, Steps } from '@astrojs/starlight/components';
9+
10+
:::note[Acknowledgments]
11+
This guide is based on community feedback in [GitHub Issue #616](https://github.com/pgflow-dev/pgflow/issues/616).
12+
:::
13+
14+
This guide covers running pgflow on self-hosted Supabase instances. Self-hosted deployments differ from Supabase.com in several ways this guide addresses.
15+
16+
## Requirements
17+
18+
Before running pgflow on self-hosted Supabase, ensure you have:
19+
20+
- **pgmq 1.5.0+** - Required for pgflow. May require upgrading your Supabase Postgres image.
21+
- **Connection pooler enabled** - Supavisor must be running and accessible to Edge Functions.
22+
- **Manual pgflow setup** - Since the Supabase CLI doesn't work with self-hosted, follow the [Manual Installation guide](/reference/manual-installation/) to set up migrations and functions.
23+
24+
## Upgrade Postgres Image
25+
26+
The default Supabase docker image may ship with an older pgmq version. If you see errors related to missing `pgmq` functions after installing pgflow migrations, upgrade your Postgres image.
27+
28+
In your `docker/docker-compose.yml`, update the `db` service image:
29+
30+
```yaml
31+
db:
32+
image: supabase/postgres:15.14.1.098
33+
```
34+
35+
<Aside type="tip">
36+
A known working version for the 15.x branch is `15.14.1.098`. PostgreSQL 17 is
37+
also supported (v17.6.1.100 or later).
38+
</Aside>
39+
40+
After updating, restart your containers:
41+
42+
```bash frame="none"
43+
docker compose down
44+
docker compose up -d
45+
```
46+
47+
## Database Connection
48+
49+
Self-hosted Supabase does not auto-configure `EDGE_WORKER_DB_URL`. You must set this environment variable explicitly on your Edge Functions.
50+
51+
The connection string format for self-hosted Supabase:
52+
53+
```bash frame="none"
54+
EDGE_WORKER_DB_URL=postgresql://postgres.${POOLER_TENANT_ID}:${POSTGRES_PASSWORD}@supavisor:${POOLER_PROXY_PORT_TRANSACTION}/postgres
55+
```
56+
57+
Where:
58+
59+
- `POOLER_TENANT_ID` - Your pooler tenant ID (set in your `.env` file)
60+
- `POSTGRES_PASSWORD` - Your Postgres password
61+
- `POOLER_PROXY_PORT_TRANSACTION` - The transaction pooler port (default: `6543`)
62+
63+
<Aside type="note">
64+
The hostname is `supavisor` (not `pooler` which is used by the Supabase CLI
65+
local development environment).
66+
</Aside>
67+
68+
Set this environment variable in your Edge Function deployment configuration. See [Database Connection](/deploy/database-connection/) for all connection options including SSL configuration.
69+
70+
## Function Deployment
71+
72+
The Supabase CLI is designed for Supabase.com and local development. For self-hosted deployments, deploy Edge Functions manually:
73+
74+
<Steps>
75+
1. Copy your function directories to `./volumes/functions/` in your Supabase project
76+
77+
2. Mount the volumes in your `docker-compose.yml` under the `functions` service
78+
79+
3. Ensure your flows are also accessible (either in the functions volume or a separate mounted volume)
80+
81+
4. Restart the Edge Functions container
82+
</Steps>
83+
84+
### Docker Compose Changes
85+
86+
Apply these changes to your `docker/docker-compose.yml`:
87+
88+
```diff
89+
--- a/docker-compose.yaml
90+
+++ b/docker-compose.yaml
91+
@@ -420,6 +420,7 @@ services:
92+
restart: unless-stopped
93+
volumes:
94+
- ./volumes/functions:/home/deno/functions:Z
95+
+ - ./volumes/flows:/home/deno/flows:Z
96+
- deno-cache:/root/.cache/deno
97+
depends_on:
98+
kong:
99+
@@ -438,6 +439,8 @@ services:
100+
SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
101+
# TODO: Allow configuring VERIFY_JWT per function.
102+
VERIFY_JWT: "${FUNCTIONS_VERIFY_JWT}"
103+
+ # Allow pgflow workers to resolve pg connections via supavisor
104+
+ EDGE_WORKER_DB_URL: postgresql://postgres.${POOLER_TENANT_ID}:${POSTGRES_PASSWORD}@supavisor:${POOLER_PROXY_PORT_TRANSACTION}/postgres
105+
command:
106+
[
107+
@@ -495,7 +498,7 @@ services:
108+
# Comment out everything below this point if you are using an external Postgres database
109+
db:
110+
container_name: supabase-db
111+
- image: supabase/postgres:15.8.1.085
112+
+ image: supabase/postgres:15.14.1.098
113+
restart: unless-stopped
114+
```
115+
116+
Key changes:
117+
118+
- **flows volume** - Mount your flows directory so Edge Functions can access them
119+
- **EDGE_WORKER_DB_URL** - Set the database connection string for pgflow workers
120+
- **postgres image** - Upgrade to a version with pgmq 1.5.0+
121+
122+
## Running Migrations
123+
124+
When applying pgflow migrations to a self-hosted database, you may need to bypass SSL verification:
125+
126+
```bash frame="none"
127+
PGSSLMODE=disable npx supabase migrations up --db-url $DB_URL
128+
```
129+
130+
Where `DB_URL` is your direct Postgres connection string (not the pooler URL).
131+
132+
## See Also
133+
134+
- [Database Connection](/deploy/database-connection/) - Connection configuration options
135+
- [Database SSL](/deploy/database-ssl/) - SSL configuration for production
136+
- [Update pgflow](/deploy/update-pgflow/) - Upgrading pgflow on self-hosted

0 commit comments

Comments
 (0)