Migrate from Supabase cloud to self-hosted Supabase

Moving from Supabase Cloud to self-hosted Supabase is a documented path that restores schema, data, roles and auth users, but JWT keys, providers, Edge Functions, Storage and domains must be rebuilt. This page plans that work.

On this page

Why teams move a Supabase Cloud project to self-hosted Supabase

Teams usually reach this decision at a renewal, during a cost review, when a data residency rule applies, or when they want less dependence on one vendor. The move is supported by Supabase's documented restore path, but it needs real reconfiguration: JWT secrets, auth provider settings, Edge Functions, Storage objects, SMTP and custom domains must all be set up again on the new instance. Treat it as a re-platforming project, not a database export.

The work is usually done by platform or backend engineers with a DBA on hand, since the restore runs through psql and the database is where most of the risk sits. The self-hosted stack is the Apache-2.0 Docker Compose configuration published in the supabase/supabase repository, which bundles Postgres, Auth, PostgREST, Realtime, Storage and the other services. Effort depends on which features your project uses. A project that only uses tables, row-level security and Auth needs far less work than one that relies on Edge Functions, many Storage buckets or several OAuth providers. Inventory those features before you estimate anything, and confirm the current service versions against the changelog.

Plan for the support model before you cut over. Self-hosted Supabase is community-supported through GitHub Discussions, GitHub Issues, Discord and Reddit, and Supabase directs enterprises to its Growth Team. Each self-hosted instance also runs as a single project, so Studio does not manage multiple organizations or projects. Ask who on your side will own upgrades, backups and on-call response, and confirm in writing what, if anything, a vendor or partner will cover.

Which Supabase Cloud capabilities move cleanly and which need rework

This table maps each Supabase Cloud capability to its self-hosted equivalent and labels it as clean, needs rework or gap. Read the status column first, then the notes, to decide which parts of your project can move as is and which need engineering time before cutover. Items marked gap are not available on a self-hosted instance and need a replacement plan.

CapabilitySelf-hosted statusWhat to expect
Postgres schema, data, RLS policies, functions and triggersCleanRestored from the three dump files with psql. Test the restore on a non-production instance first, since newer platform Postgres versions can add settings the self-hosted instance lacks.
RolesCleanExported with supabase db dump --role-only. Use the Supabase dump rather than raw pg_dump, which includes internals that cause permission errors on restore.
auth.users recordsCleanRestored as part of the data dump, so user rows carry over. Sessions do not, and users must sign in again.
JWT secrets and API keysNeeds reworkSecrets differ between the platform and self-hosted instances. Generate a new key pair and update every client and server that holds the old keys.
Auth provider settingsNeeds reworkProvider configuration is not restored. Re-enter each provider, and update OAuth redirect URLs from the supabase.co hostname to your self-hosted hostname.
Storage objectsNeeds reworkCopy with rclone over the S3 endpoint, since copying files into volumes/storage skips Storage metadata. Create destination buckets before copying.
Edge FunctionsNeeds reworkNot restored. Redeploy function code to the self-hosted Edge Runtime and recheck any platform-specific secrets or environment variables.
SMTP settingsNeeds reworkNot restored. Configure your own mail provider and test password reset and confirmation emails before cutover.
Custom domainsNeeds reworkNot restored. Set up DNS, TLS and the self-hosted API gateway hostname, then update application configuration.
RealtimeNeeds reworkSelf-hosted Realtime is a Docker service that you configure and can remove if unused. Test subscriptions and confirm the pinned version fits your application.
BranchingGapNot available when self-hosting. Plan an alternative staging workflow, such as a second self-hosted instance.
Managed backups and PITRGapNot available when self-hosting. Build backup and restore procedures before go-live, as described in the backup replacement guidance.
ETL and Management APIGapNot available when self-hosting. Scripts or automation that call the Management API must be rewritten against your own services.

How the migration runs from inventory to decommission

The sequence moves a Supabase Cloud project to a self-hosted instance in stages, so each stage produces evidence that the next one can rely on before any production user is moved.

  1. Inventory every feature the project uses

    Your team lists the Postgres schema, RLS policies, functions, triggers, auth providers, Edge Functions, Storage buckets, SMTP settings, custom domains and OAuth redirect URLs in use, and marks which hosted features the app depends on, such as branching, backups, PITR or the Management API, which self-hosted Supabase does not offer. The output is a written inventory with an owner for each item, plus a list of anything that must be rebuilt rather than copied. Done when the inventory is reviewed and every item has a target.

  2. Rehearse the restore on a non-production instance

    Your platform or database team stands up a self-hosted Supabase instance with Docker Compose on non-production infrastructure. They create the three dump files with supabase db dump (--role-only, a plain dump and --data-only --use-copy) and load them with psql in a single transaction, using ON_ERROR_STOP=1 and session_replication_role set to replica during the data import. Test the restore on a non-production instance first, because a newer platform Postgres or Auth version can add settings, columns or tables the self-hosted instance lacks. Done when the restore completes without errors and row counts and policies match the source.

  3. Run a pilot with test users and staged data

    Your team points a limited set of test clients at the rehearsal instance and exercises sign-in, row-level access, Edge Functions and Storage paths against it. They reset JWT secrets and API keys, re-enter auth provider settings and confirm OAuth redirect URLs now use the self-hosted hostname. The output is a defect log with each issue assigned and retested. Done when the pilot passes the inventory checks without manual database edits.

  4. Run the self-hosted instance in parallel

    The production-bound self-hosted instance receives a fresh restore while the Supabase Cloud project stays live, and your team compares schema, data and access results between the two on a schedule you set. Because JWT secrets differ, platform tokens stop working on the new instance, so client apps must plan for users signing in again. Done when comparisons show no unexplained differences and monitoring and backups are running on the new instance.

  5. Copy Storage objects with rclone over S3

    Your team creates destination buckets on the self-hosted instance first, then uses rclone to copy objects from the platform S3 endpoint to the self-hosted S3 endpoint. Copying files straight into volumes/storage is not enough, because that skips Storage's metadata records. The output is an object count and checksum comparison per bucket. Done when every bucket matches the source and a sample of files opens correctly through the application.

  6. Cut over the domains and users

    During a planned window, your team freezes writes on the Supabase Cloud project, takes a final data dump, applies the last changes to the self-hosted instance, switches DNS and client configuration to the new hostname, and restores custom domains and SMTP. Confirm the change with a smoke test of sign-in, reads, writes and file access. Done when the application works end to end on the self-hosted domain and the change record is signed off.

  7. Decommission the platform project after validation

    Once the self-hosted instance has run in production with monitoring and tested backups, your team exports any remaining records the retention policy requires, documents the final state, and retires the Supabase Cloud project. Confirm the deletion steps and what happens to backups with the vendor before deleting, because retention rules belong to the provider. Done when the retention evidence is filed and the project no longer receives traffic.

How the database and dump files move with the Supabase CLI and psql

The database move runs in three dump files, and the order of restore matters. Supabase's restore guide has you create them with supabase db dump: one role-only file, one plain schema file, and one data file made with --data-only --use-copy. The Supabase documentation warns against using raw pg_dump for this job, because a plain dump includes Supabase's internal schemas and objects, and restoring those onto a self-hosted instance produces permission errors. Keeping the CLI dump is the safer default, and the reader should check that roles are restored before the schema that depends on them.

On the self-hosted side, load the three files with psql using ON_ERROR_STOP=1 inside a single transaction, so any failure stops the restore and leaves nothing half-applied. The guide also sets session_replication_role to replica for the data import so triggers do not fire and re-write rows that are already in the dump. Plan to run this on a non-production instance first, and confirm row counts and RLS policies against the cloud project before anyone points an application at the new database.

The largest version risk sits in the database itself. The restore guide warns that a newer platform Postgres or Auth version can add settings, columns or tables that the self-hosted instance does not have, so a restore can fail or behave differently even when the dump is clean. Compare the platform's Postgres version with the default in your self-hosted configuration, and review the self-hosted changelog for the Docker configuration you intend to run. Ask the team who owns that comparison and record the result before the cutover window is set.

Data, identities and integrations to rebuild after the restore

A platform restore moves schema, rows, policies and the auth.users table, but several pieces stay behind and must be rebuilt by hand on the self-hosted instance. Storage objects, sign-in sessions, OAuth redirects, email delivery, Edge Functions and domains each need their own check before users reach the new stack.

Storage objects and buckets

Storage files are not restored with the database dump. Copy them with rclone between the platform's S3 endpoint and the self-hosted S3 endpoint, because placing files directly into volumes/storage skips the metadata records Storage needs. Create every destination bucket before copying, then compare object counts and sizes per bucket against the source.

Auth users and sign-in sessions

The restore carries over auth.users, so user records arrive, but platform tokens stop working because the JWT secrets differ. Every user must sign in again on the self-hosted instance. Tell support teams and mobile app owners to expect re-authentication prompts on day one, and check that sign-up, password reset and sign-in work with a test account before cutover.

OAuth redirect URLs

OAuth providers redirect to the hostname registered for the project, which is usually a *.supabase.co address on the platform. Update the redirect URLs in each provider's console to the self-hosted hostname, and confirm that the provider client IDs and secrets are configured again on the new instance. A redirect left pointing at the old host will fail silently for social sign-in users.

SMTP settings for auth email

SMTP configuration is not restored, so confirmation, invitation and password reset emails stop until you add a sending server to the self-hosted environment. Confirm the sender domain, SPF and DKIM records, and that test messages reach mailboxes, not spam folders. Also confirm who owns the mail provider account and its sending limits, since that relationship does not move with the database.

Edge Functions

Edge Functions are not part of the database restore, so each function must be copied into the self-hosted functions directory and redeployed on the Edge Runtime. Check every function for hardcoded platform URLs, project keys and secrets, and move those values into the self-hosted .env file. Test each function against the restored data before routing production traffic to it.

Custom domains and API endpoints

Custom domains are configured per instance and must be set up again on the self-hosted gateway, including TLS certificates. Update every client app, webhook and third-party integration that calls the old API URL, and confirm the anon and service keys issued by the new instance are the ones deployed to clients. Keep the old domain running for a period, if your change plan allows it, so clients can switch on their own schedule.

How the work differs by project size and starting point

A small project with a modest database, few Storage objects and no Edge Functions usually has the shortest path. The restore covers schema, data, roles, RLS policies, functions, triggers and auth.users, and the remaining work is mostly reconfiguration: new JWT keys, a new hostname and any SMTP settings. The Docker Compose stack can be trimmed, because Supabase's self-hosting guide says unused services such as Realtime, Storage, imgproxy or Edge Runtime can be removed from docker-compose.yml. The published minimum is 4 GB RAM, 2 CPU cores and a 40 GB SSD, and the recommended size is 8 GB RAM, 4 cores and 80 GB.

  • Service trimming: Remove Realtime, Storage, imgproxy or Edge Runtime only if your application never calls them, and retest after each removal.
  • Hardware floor: Start from the 4 GB RAM, 2 core, 40 GB SSD minimum for a test instance, then size production against your own load.
  • Object copy: A few objects can be copied with rclone in one pass, but destination buckets must exist first.
  • Users: Expect every user to sign in again, because platform tokens stop working once JWT secrets differ.
  • Testing: Run the restore on a non-production instance first, as the restore guide recommends.

Confirm with your team which services the application actually calls before deleting any container from the Compose file.

What drives the cost and duration of the move

This table lists the factors that most change the effort of moving a Supabase Cloud project to self-hosted Supabase, why each matters, and how to keep it manageable. Read it before asking for a quote, because each row maps to a question you can put to your implementation partner or your own team.

DriverWhy it changes effortHow to reduce it
Database sizeDump, transfer and restore time grow with data volume, and the restore must run in one transaction with ON_ERROR_STOP=1, so a failure late in a large import means a rerun.Archive stale data before the move, test restore timing on a non-production instance, and confirm the disk sizing against the minimum and recommended values in the Docker guide.
Storage object count and sizeStorage objects must be copied with rclone over the S3 endpoint, and destination buckets must exist first, so object count drives copy time and error handling.Inventory buckets and object counts early, create target buckets ahead of time, and copy in verified batches rather than one large job.
Number of Auth providers and usersAuth provider settings, SMTP and OAuth configuration must be set up again on the self-hosted instance, and each provider needs its own redirect and secret checks.List every enabled provider and template, confirm which ones your apps still use, and retire unused ones before the cutover.
Edge Functions to re-deployEdge Functions are not carried over by the restore, so each one must be re-deployed and tested against the self-hosted Edge Runtime.Count functions, remove dead ones, and note any that depend on platform-only features or external secrets.
RLS policies, functions and triggersThe restore carries these across, but a database that relies heavily on triggers or security definitions needs functional testing, since triggers are suppressed during the data import.Run application test suites against the restored copy, and review any trigger that writes audit or derived data.
Hostname, OAuth and JWT changesJWT secrets differ between platform and self-hosted, so tokens stop working and users must sign in again. OAuth redirect URLs must move from *.supabase.co to the new hostname.Plan a user communication, update every OAuth provider console and client configuration, and schedule the cutover with a rollback path.
Platform version driftThe self-hosted Docker configuration 0.8.3 pins Auth v2.197.0, PostgREST v14.18 and Realtime v2.143.3, and the restore guide warns that newer platform Postgres or Auth versions can add settings or tables the self-hosted instance lacks.Compare the platform's Postgres and Auth versions with the pinned upstream versions before restoring, and record the check in the migration plan.
Team Docker and Postgres experienceOperating Compose, secrets generation, Postgres roles and backups is ongoing work, and self-hosted Supabase is community-supported, so troubleshooting falls to your team or a paid partner.Assess skills honestly, train or pair staff before the move, and ask any partner to document runbooks for upgrades and restores.

Questions teams ask before moving off Supabase Cloud

What drives the cost of moving from Supabase Cloud to self-hosted Supabase?

The cost is driven by the work and the infrastructure you take on, not by a published migration fee. Recurring costs include the servers or cloud instances that run the Docker Compose stack, storage for the database and Storage objects, backup storage and network egress. One-time costs include the migration rehearsal, reconfiguring auth providers, Edge Functions and domains, and testing. Costs rise with data volume, the number of Storage objects and how many services you keep running. To compare fairly, check your current plan and usage on the Supabase pricing page, then ask any implementation partner for a quote built from a written scope.

How long does a migration from Supabase Cloud to self-hosted Supabase take?

The duration depends on database size, the number of Storage objects, how many Edge Functions and auth providers you use, and how much testing your release process requires. Supabase's restore guide recommends rehearsing the restore on a non-production instance first, and that rehearsal usually sets the schedule. Ask for a timeline in the written scope rather than relying on a general estimate, and confirm it against your own environment and change windows.

Can our own engineers migrate Supabase Cloud to self-hosted Supabase without outside help?

Yes, if your team has working knowledge of Postgres, Docker Compose, secrets handling and reverse proxies. The documented path uses the Supabase CLI to dump roles, schema and data, psql to restore them, and rclone to copy Storage objects. The harder parts are rebuilding what the restore does not carry over, such as JWT secrets, auth provider settings, Edge Functions, SMTP and custom domains, and then operating the result. Self-hosted Supabase is community-supported, so your team would own that operating work after cutover.

What does the migration need from our team and our infrastructure?

You need a named owner for the database and auth cutover, access to the Supabase Cloud project, a target environment that meets the minimum requirements in Supabase's Docker guide, and a window for user communication. Your application team must update client configuration, OAuth redirect URLs and any hardcoded *.supabase.co endpoints. Security must set strong secrets with the generation scripts and not use the placeholder values in .env.example. Confirm these responsibilities in the scope before work begins.

Do users stay signed in after moving to self-hosted Supabase?

No, users must sign in again. JWT secrets differ between the Supabase platform and a self-hosted instance, so tokens issued by the platform stop working after cutover. Your restore keeps auth.users, but sessions and tokens are re-established on the new instance. OAuth providers also need their redirect URLs changed from the *.supabase.co hostname to your self-hosted hostname. Plan a sign-in notice for users and test the flow on a rehearsal instance before cutover.

What happens to backups after cutover?

Supabase Cloud managed backups and point-in-time recovery do not exist on a self-hosted instance, so you must set up your own. Keep the Supabase Cloud backups and export files for as long as your retention policy requires, and verify that you can still read them. On the new instance, schedule database dumps, archive Storage objects and run restore tests on a schedule. Your team or implementation partner owns those backups from cutover onward, so define retention, encryption and restore testing in the written scope.

Who supports and upgrades self-hosted Supabase after the move?

Support comes from the community, through GitHub Discussions, GitHub Issues, Discord and Reddit, according to Supabase's self-hosting docs. Enterprises are directed to contact Supabase's Growth Team. Upgrades are your responsibility: each Docker configuration release pins specific Auth, PostgREST and Realtime versions, and some releases, such as those that migrate Storage's database, require a backup first. DeployOpen can plan, implement, back up, upgrade and document the stack, and provides ongoing support under a retainer, with scope agreed in writing.

What usually goes wrong and how to prevent it

Most failed Supabase migrations trace back to a handful of configuration and sequencing mistakes rather than to the data itself. The cards below cover secrets, version alignment, Storage metadata, login redirects, upgrade safety and what happens after the cutover, so each can be checked before you switch traffic.

Keeping the placeholder secrets

The Docker configuration ships with placeholder values in .env.example, and starting the stack with them leaves the database, JWT signing and dashboard access guessable. Generate fresh secrets with the scripts Supabase provides, and set a real DASHBOARD_PASSWORD before Studio is reachable from any network. Confirm that no copy of the example file is in use on the server and that the JWT key pair was generated for this instance, not carried over from the platform project.

Mismatched Postgres and service versions

The platform project and the self-hosted stack can run different Postgres and Auth versions, and the restore guide warns that a newer platform version can add settings, columns or tables the self-hosted instance does not have. Compare the platform version with the pinned versions in your Docker configuration before dumping, and rehearse the full restore on a non-production instance. Treat any schema difference found in rehearsal as a blocker until it is explained.

Storage copied without metadata

Copying files straight into the Storage volume leaves objects on disk with no matching metadata records, so the API cannot list or serve them correctly. Move objects with rclone between the platform S3 endpoint and the self-hosted one, and create destination buckets first. After the copy, compare object counts and sizes per bucket and download a sample of files through the application to confirm they resolve.

OAuth and redirect URLs still pointing at supabase.co

Provider callbacks, email links and client configuration often still reference the platform hostname after cutover, so sign-in fails or sends users to a project that no longer receives traffic. Update OAuth redirect URLs with each identity provider to the self-hosted hostname, and review SMTP settings and custom domains, which must also be set up again. Because JWT secrets differ, expect every existing session to end and plan a sign-in notice for users.

Skipping backups before the 0.8.3 Storage migrations

The 0.8.3 release flags one-way Storage database migrations that require a database backup before updating. If an operator pulls the new configuration and recreates containers without that backup, there is no supported path back to the earlier state. Take and verify a full database backup, record the image versions in use, and read the changelog entry for each release before upgrading any running stack.

No tested rollback after decommission

Self-hosted Supabase has no managed backups or point-in-time recovery, so the platform project's safety net does not carry over. Before you delete or downgrade the cloud project, confirm that you hold a verified logical dump, all Storage objects and a documented procedure to restore them into your own stack. Decide who owns scheduled backups, how long copies are kept, and which restore test is repeated after go-live.

How to run both stacks in parallel and cut over safely

Keep the Supabase Cloud project live until the self-hosted instance has passed a full rehearsal, because the platform project is your rollback path. Restore the dumps into a non-production self-hosted instance first, as Supabase's restore guide recommends, and check the things that differ: platform Postgres and Auth versions may add settings, columns or tables your instance lacks. Run your own test suite against the restored copy, including RLS policies, Edge Functions and Storage access, before you plan the production window. Confirm which Supabase CLI version produced the dumps and which Docker configuration release you deployed, since both move over time.

Plan the final data load around a short write freeze. Put the application into read-only mode or disable the write paths for the duration of the final supabase db dump and the psql restore with ON_ERROR_STOP=1, then copy Storage objects with rclone after the destination buckets exist. Measure how long your own rehearsal takes and use that figure, not an assumed one, to set the freeze window with stakeholders. If writes must continue, decide in advance how rows created on the platform during the gap will be re-synced, and who owns that reconciliation.

The switch itself has three coordinated changes: point clients at the self-hosted hostname, load the new JWT secret and API keys, and update OAuth redirect URLs from the *.supabase.co domain to your own. Existing platform tokens stop working once the keys change, so users sign in again and mobile or desktop clients must be released with the new endpoint. Re-check SMTP settings and custom domains, which the restore does not carry over. Keep the platform project paused rather than deleted until the rollback window closes, and treat the self-hosted Docker release cadence as a standing constraint: pin the configuration and service versions you tested, and rehearse each upgrade before it reaches production. Confirm the exact backup requirements in the changelog before any update that changes Storage database migrations.

How DeployOpen scopes, runs and supports the Supabase migration

DeployOpen plans, implements, integrates, hardens, backs up, documents and supports self-hosted open-source platforms inside your own infrastructure. For this migration, we work from a written scope that covers the platform dump, the restore, the Storage copy, and the settings that must be set up again on the self-hosted instance.

How we scope

  • The written scope lists the Supabase Cloud projects, databases, Storage buckets and Edge Functions included in the migration.
  • It states which auth providers, SMTP settings, custom domains and OAuth redirect URLs must be reconfigured on the new hostname.
  • Engagements are fixed-scope, so deliverables and timelines are agreed in writing before any migration work starts.

How we build

  • We deploy self-hosted Supabase with Docker Compose in your cloud account, data center or air-gapped network, and generate secrets rather than using placeholders.
  • We rehearse the dump and restore on a non-production instance first, checking for settings the newer platform Postgres or Auth version adds.
  • We copy Storage objects with rclone, confirm destination buckets exist, and verify object counts against the source before cutover.

How we hand over

  • We document the cutover runbook, the restore steps, the JWT and API key changes, and the list of features that do not carry over.
  • We deliver a test record showing which tables, policies, functions, triggers and users were restored and checked.
  • We walk your team through the upgrade path for Docker configuration releases, including the database backup required before one-way Storage migrations.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer, scoped separately from the migration.
  • Retainers can cover pulling and recreating pinned upstream service versions, reviewing changelog security fixes and applying them.
  • Self-hosted Supabase is community-supported, so we confirm which operational responsibilities your team keeps before the retainer begins.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.