Getting self-hosted Supabase running takes an afternoon. Keeping it patched, backed up and secure for years is where the time goes, and it's the part most guides skip.
We run self-hosted Supabase on Google Cloud for Hexis, where the database had to live in the client's own cloud project and neither it nor the admin tools could be reachable from the public internet. Our GCP series covers how we built that. This post is the general version, for any cloud: what the stack contains, when self-hosting is worth it, what it costs, the work of running it, and the checklist we go through before a self-hosted setup takes real traffic.
Facts about Supabase's Docker setup come from its self-hosting docs, checked on October 27, 2026. The setup changes often, so check the docs before you rely on a detail.
What's in the stack
Supabase isn't one server. The official Docker Compose setup runs a set of services that together make up what you use on supabase.com:
| Service | What it does |
|---|---|
| Studio | The dashboard |
| API gateway | Routes requests to the services behind it. Envoy by default since v0.8.0, or Kong |
| Auth | Sign-ups, logins and sessions, issuing JWTs |
| PostgREST | Turns your database schema into a REST API |
| Realtime | Sends database changes, broadcasts and presence to connected clients |
| Storage | A file API, with permissions kept in Postgres |
| imgproxy | Image processing |
| postgres-meta | The API Studio uses to manage Postgres |
| Postgres | The database. Postgres 17 by default since v0.6.0 |
| Edge Runtime | Runs your Edge Functions on Deno |
| Supavisor | The connection pooler |
| Logflare | Log management. Optional and off by default, along with Vector, which feeds it |
Supabase lists the minimum for running all of it as 4 GB of RAM, 2 CPU cores and 40 GB of SSD, and recommends 8 GB, 4 cores and 80 GB or more. If you don't use Realtime, Storage, imgproxy or Edge Runtime, the docs say you can remove them from docker-compose.yml.
You don't have to run everything. At Hexis the app already had its own API and sign-in, so we only needed Studio and postgres-meta, pointed at a Cloud SQL database. Every service you drop is one less thing to upgrade and secure.
What the platform has that self-hosting doesn't
Per the docs, a self-hosted install is a single project, and Studio doesn't support multiple organizations or projects. Most settings live in environment variables rather than the dashboard. Branching, advanced metrics beyond logs, managed backups and point-in-time recovery, analytics and vector buckets, ETL and the Management API aren't available. Support comes from the community on GitHub, Discord and Reddit, and Supabase points enterprises to its sales team. On the plus side, the docs state that self-hosted Supabase doesn't phone home or collect telemetry.
When self-hosting makes sense
It's worth it when you have a requirement the managed platform can't meet:
- Your data has to live in your own cloud account. Supabase Cloud lets you pick a region, but some clients need the database inside their own project for audits, contracts or data residency rules. That was one of Hexis's requirements.
- Nothing can be on the public internet. We keep databases and admin tools on private networks and reach them through a VPN.
- You need a database setup the platform doesn't offer. Our multi-region PostgreSQL runs three writable nodes kept in sync with pglogical.
- You already run large PostgreSQL deployments and have people who operate them.
It usually isn't worth it when:
- You're building an MVP. Managed Supabase is cheaper and faster until you have a concrete reason to leave.
- Nobody owns operations. Someone has to do upgrades, watch alerts and answer the pager. If that's nobody, it ends up being everybody, at the worst moment.
- You depend on platform features such as branching, point-in-time recovery or several projects under one dashboard.
- You want vendor support for the stack.
What it costs
Start with the managed price, because that's what you're comparing against. On October 27, 2026, Supabase's pricing page listed the Pro plan from $25 a month, including $10 of compute credits (enough for one Micro instance), and the Team plan from $599 a month. Compute add-ons start at $10 a month for Micro, $15 for Small and $60 for Medium, and point-in-time recovery costs $100 a month per 7 days of retention.
A self-hosted bill has more lines:
- Compute for every environment you run, sized to the requirements above.
- The database: either the bundled Postgres on your own disks, or a managed database. Managed is less work but comes with limits. Cloud SQL, for example, has no superuser and a fixed extension list, which we cover in the FAQ on our GCP post.
- Object storage for files, plus egress.
- Backups, stored somewhere other than the servers they protect.
- An SMTP provider for auth emails.
- Logs and monitoring.
- Engineering time, the biggest line and the one people leave out.
For a sense of scale, each self-managed PostgreSQL node in our multi-region setup costs about $120 to $140 a month with disk on Compute Engine, against the $400 to $500 a month we estimated per Cloud SQL replica. Running the database yourself is cheaper on the invoice, but you own its upgrades and backups.
The time adds up faster than the servers. At our rates of $100 to $150 an hour, two hours of upkeep a month is $200 to $300, eight to twelve times the Pro plan's starting price. Self-hosting saves money when the managed bill is already large, or when you'd be running big PostgreSQL infrastructure anyway. Our Supabase cost breakdown prices three example setups both ways, line by line. If you're still pricing the app itself, our estimator gives a planning range for the build.
Running it
Upgrades
Supabase publishes stable snapshots of the Docker setup about once a month. Its update.sh script updates a deployment in place with a three-way merge, so your .env values and local edits survive and conflicts get flagged. You can change individual image tags, but the docs warn that compatibility between versions isn't guaranteed.
Two points from the updating guide matter most:
update.shdoesn't back up Postgres or Storage data. Take your own backups first.- Some releases need a manual step, such as a Postgres major upgrade. Postgres 17 became the default in v0.6.0, and the guide says not to recreate a Postgres 15 deployment straight onto 17.
What works for us: pin versions, read the changelog for every release you cross, upgrade staging first, and keep a written runbook.
Backups
Nothing is backed up for you, so decide up front:
- Database: daily backups at minimum, plus WAL archiving if you need point-in-time recovery. If the database runs on a managed service, use its backups. On Cloud SQL we keep 35 daily backups and 7 days of point-in-time recovery (our configuration).
- Files: Storage keeps files on the local filesystem by default. Back up that volume, or better, the bucket behind an S3 backend.
- Restores: a backup you haven't restored is a guess. Restore into a scratch environment on a schedule.
Monitoring and logs
Logflare and Vector are off by default. Turn them on with sh run.sh config add logs, or ship container logs to your own stack. We use Google Cloud's monitoring with Grafana dashboards and Slack alerts. Whatever you use, alert on:
- Disk, memory and CPU on every host
- Postgres connections against
max_connections - Replication slots: Realtime reads changes from a logical replication slot, and an inactive slot holds on to WAL and can fill the disk
- Error rates on the API gateway and Auth
- TLS certificate expiry
Auth email
Auth sends sign-up confirmations, magic links and password resets, and the docs say you need a production-ready SMTP server for them. They recommend AWS SES. You set SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_ADMIN_EMAIL and SMTP_SENDER_NAME in .env and restart the services. Set up SPF, DKIM and DMARC for the sending domain too, or the emails land in spam.
OAuth providers need HTTPS with a valid certificate, and each app's redirect URLs have to be allowed in the Auth settings.
Storage
For production, move off the local filesystem to an S3-compatible backend such as AWS S3 or Cloudflare R2. For object storage you run yourself, Supabase now recommends RustFS for new deployments and keeps MinIO only for existing ones, since MinIO no longer publishes open-source Docker images. Supabase's docs don't mention Google Cloud Storage. Its XML API works with some S3 tools through HMAC keys, so test uploads of real files, including large ones, before you depend on it.
Realtime
Realtime's Postgres Changes feature reads from a logical replication slot. Supabase's docs note that changes are processed on a single thread to keep them in order, and that every event is checked against each subscriber's permissions. Past about 3,000 concurrent subscribers on the same changes, they recommend Broadcast instead.
Edge Functions
There's no deploy command when you self-host. Functions live in volumes/functions, one folder each. You copy the code there and run sh run.sh restart functions, or sh run.sh recreate functions after changing environment variables. Memory and time limits are set per worker in main/index.ts. Hosted functions run in several regions; a self-hosted instance runs wherever you put it. Put the copy-and-restart step in CI from day one, so a deploy never depends on someone's laptop.
Security
The defaults are built for getting started, not for production:
- Replace every placeholder secret before the first start. The docs say never to start with the values in
.env.example. Generate them with the scripts inutils/and keep them in a secrets manager. We use Infisical. - Use the API keys as intended. The publishable key is for clients. The secret key stays on servers. Rotating them doesn't sign anyone out, but regenerating the signing key pair invalidates every ES256 session, so plan a window for that.
- Put HTTPS in front. Supabase serves plain HTTP by default. The docs recommend a reverse proxy such as Caddy or Nginx, and a cloud load balancer that terminates TLS works too.
- Keep Studio private. Studio sits behind a single basic-auth login and can do anything to your database. Keep it behind a VPN or an IP allowlist, the way we do with a VPN and Cloud Armor.
- Keep Postgres off the network. By default it's only reachable through the pooler. If you open a direct port, restrict it with firewall rules.
- Write Row Level Security policies. Anything the API exposes can be reached with the publishable key, so every exposed table needs policies. Our RLS and security checklist has the SQL to find tables and policies that leak.
- Patch the hosts. The operating system and Docker are yours to update too.
If you handle health data, self-hosting adds work rather than removing it. Supabase says its HIPAA controls aren't supported out of the box when you self-host, as we explain in Supabase HIPAA Compliance.
Production checklist
Before a self-hosted Supabase takes real traffic, we check that:
- Every secret is generated, unique and stored in a secrets manager.
- Services you don't use are removed from
docker-compose.yml. - HTTPS terminates in front of the API gateway, and the public URLs in
.envmatch. - Studio is only reachable over a VPN or an allowlist, with a strong password.
- Postgres and the pooler sit on a private network.
- Row Level Security is on for every table the API exposes.
- Production SMTP is set up, the sending domain is authenticated, and test emails arrive.
- Files live on an S3-compatible backend, and that bucket is backed up.
- Database backups run automatically, point-in-time recovery is on if you need it, and a restore has been tested.
- Logs and metrics leave the host, with alerts on disk, connections, replication slots and errors.
- A staging environment runs the same versions, and there's an upgrade runbook.
- The infrastructure is defined as code, so you can rebuild it from scratch. We use Pulumi with TypeScript.
- Someone owns on-call.
Running it on Google Cloud
For the Google Cloud version of all this, the series goes in order:
- Why we self-host Supabase on GCP
- Infrastructure as code with Pulumi
- Cloud SQL PostgreSQL 18 on Enterprise Plus
- VPN-only access with Cloud Armor
- Auto-scaling Supabase Studio
- Multi-region PostgreSQL with pglogical
Rather not run it yourself? We set up self-hosted Supabase on Google Cloud as a fixed-scope project, from the network to the checklist above, and can keep running it afterwards.
Frequently asked questions
Can I self-host Supabase on Kubernetes?
Yes, but not with an official setup. Supabase's self-hosting docs recommend Docker Compose and point to a community Kubernetes project (a Helm chart and an operator) that Supabase doesn't maintain. If you choose it, you're relying on the community for fixes as well as support.
How often does self-hosted Supabase need updating?
Supabase publishes stable snapshots of its Docker setup about once a month. You don't have to take every one, but the further behind you fall, the more breaking changes you cross in one go. Read the changelog for each release, back up first, and upgrade staging before production.
Do I have to run every Supabase service?
No. Supabase's Docker guide says you can remove services you don't use, such as Realtime, Storage, imgproxy or Edge Runtime, to cut resource needs. We run only Studio and postgres-meta for a client whose app has its own API and sign-in.
