Skip to main content

Overview

Supabase is an open-source backend-as-a-service built on PostgreSQL. This template deploys the full self-hosted Supabase stack on Control Plane — all services run in your own GVC with no dependency on Supabase Cloud.

Architecture

  • Postgres — Supabase-patched PostgreSQL 15 with pgvector, pg_graphql, pg_net, pgjwt, and other required extensions pre-installed.
  • Kong — API gateway and single public entry point. Routes all traffic to PostgREST, Auth, Realtime, and Storage.
  • PostgREST — Auto-generated REST and GraphQL API derived from your Postgres schema. Stateless, scales horizontally.
  • Auth (GoTrue) — Full-featured auth service supporting email/password, magic links, OAuth providers, and JWT sessions. Stateless, scales horizontally.
  • Realtime — WebSocket server that streams database change events to subscribed clients. Stateless, scales horizontally.
  • Storage — Object storage API backed by S3, GCS, or a local volume.
  • Studio — Web dashboard for managing your database, auth users, storage, and API settings.
  • pg_meta — Postgres metadata API. Runs as a sidecar inside the Studio workload.
  • PgBouncer (optional) — Connection pooler that multiplexes application connections into a smaller pool of real database connections.
  • Backup (optional) — Logical (pg_dump cron) or WAL-G (continuous WAL archiving with PITR support).

What Gets Created

  • Stateful Postgres Workload — Supabase-patched PostgreSQL with a persistent volume set.
  • Standard Kong Workload — API gateway, autoscales on RPS.
  • Standard PostgREST Workload — REST/GraphQL API, autoscales on RPS.
  • Standard Auth Workload — GoTrue auth service, autoscales on RPS.
  • Standard Realtime Workload — WebSocket change feed, autoscales on RPS.
  • Standard Storage Workload — Object storage API, autoscales on RPS (optional, enabled by default).
  • Standard Studio Workload — Web dashboard with pg_meta sidecar (optional, enabled by default).
  • Standard PgBouncer Workload — Connection pooler (optional, disabled by default).
  • Cron Backup Workload (optional) — Logical or WAL-G backup on a schedule.
  • Volume Sets — One for Postgres data; one for Storage when using the local backend.
  • Identity & Policy — Identities bound to each workload with reveal access to credential secrets, and cloud storage access when backup or S3/GCS storage is enabled.
  • Secrets — Dictionary secrets for Postgres credentials, JWT keys, and service API keys; opaque secrets for Kong routing config, SMTP settings, and OAuth provider credentials.
This template does not create a GVC. You must deploy it into an existing GVC.

Prerequisites

This template has no external prerequisites unless S3/GCS storage or backup is enabled. To install, follow the instructions for your preferred method:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations
Pulumi Icon Streamline Icon: https://streamlinehq.com

Pulumi

Declare templates in your Pulumi programs

Configuration

The default values.yaml for this template:

JWT Keys

Supabase uses JWT to authenticate requests between services and from clients.
  • jwt.secret — The signing secret for all JWTs. Must be at least 32 characters.
  • jwt.secretKeyBase — Used by Realtime (Phoenix) for cookie signing. Must be at least 64 characters. Generate with openssl rand -base64 64.
  • jwt.anonKey — Public key for unauthenticated (anonymous) client access.
  • jwt.serviceRoleKey — Privileged key that bypasses row-level security. For trusted server-side code only.
The default values are Supabase’s official published development keys and work together out of the box. Change all of them before any production deployment.
anonKey and serviceRoleKey must be valid HMAC-SHA256 JWTs signed with jwt.secret. Using mismatched keys causes bad_jwt errors across all services. Use the Supabase key generator to produce a matching set.

Kong (API Gateway)

Kong is the single entry point for all Supabase API traffic. PostgREST, Auth, Realtime, and Storage are only reachable through Kong.
  • kong.publicAccess.enabled — Expose Kong on a public external endpoint.
  • kong.publicAccess.siteUrl — The full URL clients will reach Kong at (e.g. https://api.my-app.com). Required when publicAccess is enabled. GoTrue uses this for OAuth redirect callbacks and magic link emails.
When publicAccess is disabled, internal clients use the Kong hostname within the GVC and OAuth/magic links will not work.

Postgres

You must use the supabase/postgres image. The standard postgres image is missing required extensions (pgvector, pg_graphql, pg_net, pgjwt, etc.) that GoTrue, PostgREST, Realtime, and Storage depend on.
  • postgres.password — Database superuser password. Change before deploying to production.
  • postgres.resources — CPU and memory limits/requests for the Postgres workload.
  • postgres.volumeset.capacity — Initial volume size in GiB (minimum 10). Autoscaling is configurable.
  • postgres.internalAccess.type — Controls which workloads can reach Postgres directly: same-gvc, same-org, workload-list, or none. All Supabase services connect internally. Use workload-list to also grant access to your own application workloads.

Auth (GoTrue)

  • auth.disableSignup — Set to true to prevent new user registration.
SMTP — required for magic link login, email confirmation, and password reset:
  • auth.smtp.enabled — Enable SMTP. When disabled, all signups are auto-confirmed and email flows are unavailable.
  • auth.smtp.host / auth.smtp.port — SMTP server address and port.
  • auth.smtp.user / auth.smtp.password — SMTP credentials.
  • auth.smtp.senderName / auth.smtp.senderEmail — Display name and from address for outgoing emails.
Any SMTP provider works: Gmail, SendGrid, Mailgun, Postmark, Mailtrap, etc. OAuth Providers — enable by uncommenting auth.providers and adding credentials:
Supported providers: Apple, Azure, Bitbucket, Discord, Facebook, Figma, GitHub, GitLab, Google, Kakao, Keycloak, LinkedIn, Notion, Slack, Spotify, Twitch, Twitter/X, WorkOS, Zoom. When setting up OAuth in your provider’s developer console:
  • Authorized JavaScript Origin: {kong.publicAccess.siteUrl}
  • Authorized Redirect URI: {kong.publicAccess.siteUrl}/auth/v1/callback
OAuth requires kong.publicAccess.enabled: true and a valid siteUrl. OAuth providers will not redirect to internal hostnames.

Storage

Three backends are supported:
BackendDescription
s3Stateless, horizontally scalable. Recommended for production.
gcsGCS accessed via the S3-compatible API using HMAC keys. No Cloud Account needed.
localStateful, single-replica, volume-backed. For development only.
For s3: set storage.s3.bucket, storage.s3.region, storage.s3.cloudAccountName, and storage.s3.policyName. The IAM policy must grant s3:GetObject, s3:PutObject, and s3:DeleteObject on the bucket. For gcs: create HMAC keys in the GCP console under Cloud Storage → Settings → Interoperability and set storage.gcs.accessKeyId and storage.gcs.secretAccessKey.
If using S3/GCS for backup as well, storage and backup require separate buckets, cloud accounts, and IAM policies.

Studio (Web Dashboard)

Studio is protected by username and password login and has no external access by default.
  • studio.username / studio.password — Login credentials. Change before deploying to production.
  • studio.allowedCidrs — List of CIDRs allowed to reach Studio externally. Empty by default (no external access). Use cpln workload connect for local tunnel access, or set to ["0.0.0.0/0"] to open it publicly (login is still required).

PgBouncer

PgBouncer multiplexes application connections into a smaller pool of real database connections, reducing Postgres connection overhead under high concurrency. Disabled by default.
Pool ModeDescription
transactionConnection held only for the duration of a transaction. Best for most web and API workloads. Not compatible with SET variables, temporary tables, or advisory locks.
sessionConnection held for the entire client session. Compatible with all Postgres features.
statementConnection returned after every statement. Transactions not supported.
  • pgbouncer.defaultPoolSize — Number of real Postgres connections per pool (default: 25).
  • pgbouncer.maxClientConn — Maximum number of client connections PgBouncer accepts (default: 1000).
When enabled, connect through PgBouncer rather than directly to Postgres.

Connecting

All API traffic flows through Kong. Connect your application using the Kong endpoint:
EndpointAddress
API — internal{release-name}-kong.{gvc}.cpln.local:8000
API — public{kong.publicAccess.siteUrl} (when publicAccess enabled)
Postgres — direct{release-name}-postgres.{gvc}.cpln.local:5432
Postgres — via PgBouncer{release-name}-pgbouncer.{gvc}.cpln.local:5432 (when enabled)
Key API paths routed through Kong:
ServicePath
PostgREST (REST API)/rest/v1/
Auth (GoTrue)/auth/v1/
Storage/storage/v1/
Realtime/realtime/v1/
Pass apikey: {anonKey} as a header on all requests. Use serviceRoleKey for privileged server-side calls. The Supabase client library handles auth headers automatically:

Backing Up

Two backup modes are available:
ModeMechanismBest For
logicalpg_dump cronPortable SQL dumps, smaller databases, cross-version migrations
walgContinuous WAL archiving + base backupsProduction — supports point-in-time recovery (PITR)
Set backup.enabled: true, choose a mode and provider, then fill in the corresponding provider block.
Switching backup.mode between logical and walg changes Postgres archive_mode and wal_level, which requires a Postgres restart. Plan the switch accordingly.

AWS S3

1

Create a bucket

Create an S3 bucket. Set backup.aws.bucket and backup.aws.region to match.
2

Set up a Cloud Account

If you do not have one, create a Cloud Account. Set backup.aws.cloudAccountName to its name.
3

Create an IAM policy

Create an IAM policy with the following JSON (replace YOUR_BUCKET_NAME) and set backup.aws.policyName to its name:

GCS

1

Create a bucket

Create a GCS bucket. Set backup.gcp.bucket to its name.
2

Set up a Cloud Account

If you do not have one, create a Cloud Account. Set backup.gcp.cloudAccountName to its name.
You must add the Storage Admin role to the GCP service account created for the Cloud Account.

Restoring a Backup

Logical Restore

Run from a machine with network access to Postgres (e.g. via cpln workload connect): AWS S3:
GCS:

WAL-G Restore

WAL-G restores require an empty data directory.
1

List available backups

2

Stop the Postgres workload

Stop the workload via the Control Plane console or CLI.
3

Create a new volume set

Create a fresh empty volume set for the restore target — do not reuse the existing one.
4

Run the restore

Run a one-off workload with the new volume set mounted at /var/lib/postgresql/data and execute:
5

Restart Postgres

Re-point the Postgres workload to the restored volume set and restart. After restore, update backup.aws.prefix (or backup.gcp.prefix) to a new path before re-enabling backups to avoid WAL stream conflicts with the original cluster’s archived segments.

Important Notes

  • Use the Supabase Postgres imagesupabase/postgres is required. The standard postgres image is missing extensions that GoTrue, PostgREST, Realtime, and Storage depend on.
  • JWT keys must matchanonKey and serviceRoleKey must be HMAC-SHA256 JWTs signed with jwt.secret. Mismatched keys produce bad_jwt errors. Use the official Supabase key generator to produce a matching set.
  • Change default credentials before productionjwt.secret, postgres.password, and studio.password are placeholders. Replace all of them before any production deployment.
  • OAuth requires a public siteUrl — Set kong.publicAccess.enabled: true and kong.publicAccess.siteUrl before configuring any OAuth provider.
  • Storage and backup use separate buckets — Do not share a bucket between storage.s3 and backup.aws. Each requires its own bucket, cloud account, and IAM policy.
  • Studio has no external access by default — Use cpln workload connect for local access, or set studio.allowedCidrs to open it externally.

External References

Supabase Self-Hosting Guide

Official self-hosting documentation and architecture overview

Supabase Client Libraries

JavaScript, Python, Swift, Kotlin, and other client SDK references

GoTrue (Auth) Documentation

GoTrue auth service configuration and API reference

PostgREST Documentation

Auto-generated REST API from your Postgres schema

WAL-G Documentation

WAL-G continuous archiving and PITR restore documentation

Generate Supabase API Keys

Generate matching JWT secret, anonKey, and serviceRoleKey