Migrate from Supabase Cloud to Appwrite: what the move involves
The move is a data model change, not a file copy. Supabase gives each project a Postgres database exposed through its own APIs and row-level security rules, while Appwrite organizes data into databases, collections and documents with its own permissions model. A renewal, a pricing change, a data residency requirement or lock-in can all trigger the decision, but the work starts with mapping each Postgres table, policy and trigger to an Appwrite equivalent. Teams usually plan this as a re-platforming project with a clear cutover date, not as an export and import. Platform or backend engineers do most of the work, often with a migration partner who handles the data mapping, the auth cutover and the target environment. Appwrite Migrations can import users, databases and files from a Supabase project, but the tool moves rows only partially and moves no functions at all. Edge Functions, SQL functions, triggers and any logic written against Postgres-specific features need rewriting for Appwrite's functions runtime. Confirm with the Appwrite documentation exactly which Supabase objects the current Migrations release covers before you size the work.
On effort and risk, the largest items are the function rewrite, the rewrite of client queries and the security rules, and the parity testing that follows. Ask for a written inventory of your Supabase projects, including tables, policies, Edge Functions, cron jobs, storage buckets and auth providers, before any quote. Hash compatibility determines whether users keep their passwords. Check the password hash type your Supabase users use and confirm, against the Appwrite Users API reference, that Appwrite accepts the import without forced resets. Decide early between Appwrite Cloud and a self-hosted target, because the self-hosted option takes on operations you would otherwise not run. The Appwrite self-hosting installation guide lists the baseline requirements, and the Helm chart documentation states that the built-in datastores run a single replica without failover, so production data needs managed services or operators and a tested backup plan.
Which Supabase Cloud capabilities map cleanly to Appwrite
This table maps each Supabase Cloud capability to its closest Appwrite equivalent and marks it as clean, needs rework or gap. Read the status column first, then the notes, because most rework sits in Postgres-specific logic that Appwrite does not carry over as-is. Confirm each row against the Appwrite version you plan to run.
| Supabase Cloud capability | Appwrite equivalent | Status | What to plan for |
|---|---|---|---|
| Supabase Auth users and sign-in | Appwrite Auth with Users API import | Needs rework | Import users with their password hashes where the algorithm is supported, then test every sign-in provider and session flow before cutover. |
| Postgres tables and rows | Appwrite Databases on PostgreSQL | Needs rework | Appwrite 2.0 provisions PostgreSQL by default, but tables become Appwrite collections and documents. Rows import partially, so check types, relations and defaults after each run. |
| Row Level Security policies | Appwrite document and collection permissions | Needs rework | RLS policies and their SQL predicates must be redesigned as Appwrite permissions and server-side checks in functions. Plan a written mapping for every policy. |
| Postgres SQL functions, triggers and views | Appwrite Functions (server code) | Gap | Database functions and triggers do not move as SQL. Rewrite the logic as Appwrite Functions, then retest each event path. |
| Storage buckets and files | Appwrite Storage | Clean | Files are a standard migration target. Confirm bucket permissions, file size limits and any signed URL behavior after import. |
| Edge Functions | Appwrite Functions on Open Runtimes | Gap | Edge Functions do not transfer automatically. Rewrite each function for the Appwrite runtime and redeploy it. |
| Realtime subscriptions | Appwrite Realtime | Needs rework | Channel names and event payloads differ, so client subscription code must be updated and load tested. |
| Management API and project settings | Appwrite Console and Server SDKs | Gap | Scripts that call the Supabase Management API need replacement with Appwrite Console actions or the Appwrite API. Confirm each automation you rely on. |
| DocumentsDB and VectorsDB | Appwrite 2.0 optional services | Gap | These ship disabled and need PostgreSQL and MongoDB engines that a stock install does not deploy. Enable them only after you confirm the engine setup. |
What Appwrite Migrations moves from Supabase, and what you rebuild
Appwrite Migrations can carry users, some database content and files across from Supabase, but the server-side logic and Postgres-specific behavior around your data do not follow automatically. The cards below separate what the import path handles from what your team must rebuild and verify before cutover.
Auth users and password hashes
Appwrite's Users API accepts several imported hash types, including bcrypt, Argon2, Scrypt and SHA variants. Whether a user can sign in without a password reset depends on whether the hash Supabase exports matches one of those types. Check the hashing algorithm on a sample of accounts before scoping, and plan a reset flow for any users whose hashes do not map. Also confirm how social login identities and provider links are carried over.
Postgres rows as documents
Rows are imported into Appwrite databases as documents, so the table structure, column types, foreign keys and constraints must be translated into Appwrite collections and attributes. Expect partial coverage: anything relying on SQL views, custom types, JSON operators or relational joins needs a manual model. Run a test import on a copy of one table and compare row counts, nulls and timestamps before you commit to the mapping.
Storage files and metadata
Storage buckets map to Appwrite buckets, but file permissions, public or private flags and any folder structure encoded in object paths need explicit review. Verify checksums or sizes for a sample of files after transfer, and update every URL your clients or emails hold, because object URLs change. Confirm the file size and type limits on your target Appwrite install before moving large media.
Functions and database triggers
Supabase Edge Functions and Postgres triggers do not move with the data. Each function must be rewritten for Appwrite Functions and its runtime, and each trigger replaced by an event or a function that runs on the relevant Appwrite event. Inventory every function and trigger, record what calls it, and test the replacement against the same inputs before switching clients over.
Row Level Security policies
Supabase RLS policies are SQL rules attached to tables, and they do not transfer as code. Appwrite uses its own permission model on documents, buckets and users, so each policy must be re-expressed as collection, document or bucket permissions and then tested for the same allow and deny outcomes. Treat this as a security review item: write test cases for every role before go-live.
Realtime, domains and client code
Realtime subscriptions are written against Supabase channels, so client code must switch to the Appwrite SDK and its event model. Custom domains, redirect URLs, OAuth callback addresses and email templates also point at the old project and must be reconfigured on the target. Make a list of every client, provider console and DNS record that references Supabase, and confirm each one before cutover.
How the cutover sequence runs from inventory to decommission
The sequence turns a Supabase Cloud project into a tested Appwrite target in controlled stages, so each module moves only after its data, users and client calls have been checked. Each step produces a written artifact that the next step depends on.
Inventory the Supabase project
Document every table, view, function, Row Level Security policy, auth provider, storage bucket and client SDK call that the front end and mobile apps make. Your team leads this, with the application owners confirming which calls are production paths. The output is a field mapping sheet that pairs each Postgres table and column with an Appwrite collection and attribute, marks which Postgres-specific features (triggers, extensions, RLS logic) need rewriting, and lists every Edge Function as a rebuild item. The step is done when every client call maps to a target or is marked for retirement.
Pilot one bounded module in a non-production project
Choose one self-contained module, such as a user profile area with its own table and bucket, and move it into a separate Appwrite project on a self-hosted install that mirrors production sizing. Run Appwrite Migrations for the supported pieces, then load the remaining rows with a scripted import. Your engineers run the pilot, and the Supabase data owners confirm results. The output is a pilot report with row counts per table, a list of rows that failed type or constraint checks, a record of which user password hashes imported and which required a reset, and the rewritten query logic. The pilot is complete when counts reconcile exactly and the module works end to end in the test client.
Run a parallel period with read shadowing
Keep Supabase as the system of record and run Appwrite beside it for the pilot module, either by writing to both systems through the application layer or by reading from Supabase and comparing responses from Appwrite in the background. Log every mismatch with its request identifier and the field involved. Your engineers own the comparison tooling, and the product owner signs off on the mismatch categories. The output is a discrepancy log and a daily reconciliation summary. Move on only when mismatches are explained and no unresolved category remains for the module.
Prepare the rollback plan before the window
Write the rollback plan while the parallel run is still active, so the team knows how to return to Supabase if the cutover fails. The plan names the client configuration values that switch back, the point after which Supabase no longer receives writes, how any writes made to Appwrite during the window are reconciled, and who approves a rollback. Test the rollback once in the non-production project. The output is a signed rollback runbook and a tested reverse configuration. Confirm the approver and the communication channel with your operations team before the window is scheduled.
Execute the cutover window and switch client configuration
During an agreed window, freeze writes on Supabase, run the final incremental import of rows, users and files into the production Appwrite project, verify counts against the mapping sheet, and then release a client build that points the endpoint, project identifier and SDK calls at Appwrite. Your release engineers run the switch, and the application owner monitors error rates and authentication success. The output is a cutover log with final row counts, a signed verification checklist, and the release identifier. The cutover is complete when test accounts can sign in, read, write and upload against Appwrite, and the rollback runbook has been checked against the live state.
Decommission Supabase after a retention period
Keep the Supabase project read-only for a retention period set by your data retention policy and legal requirements, so you can recover data if a defect appears after cutover. Export a final logical dump and a storage manifest, store them under your own retention controls, and confirm that backups are retained as your policy requires. Your security and compliance leads approve deletion. The output is an archived export with checksums, a decommission record, and a list of revoked keys and removed client secrets. The step is done when the project is deleted, the keys are revoked, and the record is filed with your audit evidence.
Choosing self-hosted Appwrite or Appwrite Cloud as the target
The first decision is where the Appwrite project will run, because self-hosted Appwrite and Appwrite Cloud carry different operating and data responsibilities. Self-hosting uses the appwrite/appwrite:2.5.0 image, installed with Docker Compose version 2 and a setup wizard on port 20080, and the installation guide lists 2 CPU cores, 4 GB of RAM and 2 GB of swap as the baseline. Teams that already run Kubernetes can use the official Helm chart at oci://ghcr.io/appwrite/charts/appwrite instead. Appwrite Cloud removes the host work, with a Free plan and a Pro plan from $25 per month according to the pricing page, but the data, region and backup terms then follow the hosted service rather than your own infrastructure.
If you self-host on Kubernetes, plan production storage before the migration starts. The Helm chart's built-in PostgreSQL, Redis, ClickHouse and object storage each run a single replica without replication or failover, so the chart's defaults are not a production database tier. Decide early whether these services will be managed cloud services or operators you run, and budget for that platform work as a recurring cost. The Docker Compose sample uses the same kind of components on one host, which suits evaluation and smaller workloads but leaves the same single-point risk.
Before you commit, confirm the points the documentation does not settle for your case: the region or country where Appwrite Cloud stores project data, the backup frequency and restore process on your plan, the support response terms, and who holds the data processing agreement. For self-hosting, confirm where your own cloud account or data center places the volumes and backups, and who on your team owns patching for each release. Ask the vendor for these terms in writing, and record your answers in the migration plan so the target choice can be audited later.
What drives migration cost and duration
This table lists the factors that move the effort of a Supabase Cloud to Appwrite migration, why each one matters, and what to ask for in a written quote. Read it as a checklist: the largest drivers are usually the number of Postgres-specific rules, the count and hash types of auth users, and the choice between self-hosted high availability and Appwrite Cloud.
| Driver | Why it changes effort | How to keep it down and what to request in a quote |
|---|---|---|
| Tables and row-level security policies | Rows import into Appwrite databases with their own schema and permission model, so every Postgres policy must be re-expressed as Appwrite permissions and checked. | Inventory tables and policies first. Ask the provider to state how each policy will be mapped and tested, and whether partial row imports are included. |
| Auth users and password hash types | Users keep their passwords only if Appwrite accepts the hash algorithm used by Supabase Auth. Unsupported hashes force resets. | Export a count by provider and hash type. Ask the quote to name which users will import without reset and how the rest will be handled. |
| Storage volume and object count | Bucket contents move as files, and total size and file count drive transfer time and the cost of verifying checksums and URLs. | Measure bucket size and object count per bucket. Ask for the transfer method, verification steps and a rollback plan for the storage copy. |
| Edge Functions to rewrite | Functions do not move with the data, so each Supabase Edge Function is rebuilt on Appwrite Functions with its own runtime, triggers and secrets. | List every function with its trigger and dependencies. Ask the quote to price each function separately and to state which ones are retired instead of rebuilt. |
| Postgres-specific logic | Triggers, stored procedures, database extensions and views that rely on Postgres features need redesign in Appwrite's model. | Search the schema for functions, triggers and extensions. Ask whether the quote covers rewriting them and how business logic is retested. |
| Client apps and SDK changes | Each web, mobile or server client that calls Supabase must switch SDKs, endpoints, auth flows and realtime subscriptions. | Count client apps and release channels. Ask for the update plan, staged rollout and how old clients behave during cutover. |
| Target hosting model | Self-hosted Appwrite with high availability needs operators or a managed datastore, because the chart's built-in datastores run one replica without failover. Appwrite Cloud removes that build work but adds plan limits and billing. | Decide the target first. Ask the quote to separate infrastructure build, operator setup, backup and failover testing, and any Appwrite Cloud subscription costs. |
| Testing and cutover window | Parallel running, data reconciliation and user acceptance testing extend the schedule more than the data copy itself. | Ask for the cutover approach, reconciliation checks and the acceptance criteria written into the scope before work starts. |
What usually goes wrong in a Supabase to Appwrite move
Most failed Supabase to Appwrite moves break in predictable places: user credentials, access rules, SQL that assumed Postgres, and assumptions about what the import tool carries over. The cards below name each risk, the check that catches it, and the step that prevents it before cutover.
Password hash mismatches forcing resets
Users are only carried over without a reset if their password hashes survive the move and Appwrite can verify them. Export the Supabase auth hashes and confirm the algorithm and parameters are one that the Users API accepts, such as bcrypt or Scrypt variants. Test a sample of real logins on a staging copy before cutover, and plan a reset flow for any accounts whose hashes do not import cleanly.
Row-level security rules lost in translation
Supabase enforces access through Postgres row-level security policies, and those policies do not transfer as Appwrite permissions. Inventory every policy and map each one to Appwrite document or collection permissions, then test that a user can read only their own rows. Treat any table without an equivalent rule as closed until it is verified, because an open collection exposes client-side data directly.
Postgres-only SQL logic breaking
Views, triggers, stored procedures, extensions and SQL functions written for Postgres do not run unchanged on Appwrite's databases. Appwrite's data model is document-oriented on top of its database engine, so logic that depends on joins, triggers or custom functions must be moved into Appwrite Functions or the client. List every database object that is not a plain table before you start the import.
Functions assumed to migrate
Supabase Edge Functions are not carried over by the data import, so any function deployed to Supabase must be rewritten, redeployed and reconfigured as an Appwrite Function with its own runtime, environment variables and triggers. Count the functions in use, confirm which ones your clients call directly, and budget a test pass for each. Do not assume a function that works in Supabase will run without changes.
Single-replica datastores in production
Appwrite's Helm chart documents that its built-in PostgreSQL, Redis, ClickHouse and object storage each run a single replica without failover. A self-hosted production deployment therefore needs managed services or operators for those components, along with tested backups. Confirm the database topology and restore procedure before you point real users at the new backend.
Skipped self-hosted upgrades
Appwrite 2.0 changed the engine underneath the platform and rebuilt the Console, and existing 1.9.x installs need a migration when they upgrade. Teams that import into a version they then leave untouched fall behind the 2.5.0 release. Pin the image version, read the 2.0 release notes, schedule upgrades in a staging environment first, and record which version each environment runs.
Dropped realtime and webhook integrations
Client subscriptions, webhooks and third-party callbacks that point at Supabase endpoints stop working the moment DNS or project URLs change. Realtime clients need to subscribe to Appwrite channels, and any service that receives Supabase webhooks needs its endpoint updated. Inventory every consumer of Supabase events and test each one against the new backend before the old project is paused.
How the migration differs by starting point
A small app with a few tables, one team and a handful of auth providers usually has a narrow migration scope. The database is mostly plain tables with simple policies, the user base is modest, and file storage holds a limited set of objects. The main decisions are whether the data stays Postgres-shaped inside Appwrite's PostgreSQL-backed databases, and how much of the client code must change to use the Appwrite SDKs instead of the Supabase client. For this profile, the steps that grow are client rewiring and testing, not data volume.
- Data mapping: Tables and columns map to Appwrite collections and attributes with fewer translation decisions, so a one-off script or manual import is often enough.
- Auth cutover: Confirm which password hashes Supabase exports and whether Appwrite's Users API accepts them, so users can sign in without a reset.
- Client changes: Replace the Supabase client calls, realtime subscriptions and storage paths with the Appwrite SDK for your platform.
- Functions: Small trigger functions or cron jobs usually need a rewrite in a supported Appwrite runtime, since Edge Functions do not transfer.
- Operations: A single-team app can often run on Appwrite Cloud or one self-hosted node, but you take on upgrades and backups if you self-host.
Before committing, ask the team to list every client call and every scheduled job, because those are the items most often missed in a small project's inventory.
A multi-tenant product usually depends on row-level security policies that enforce tenant isolation inside Postgres, plus Edge Functions that run business logic close to the data. Moving this profile is a re-modeling exercise. Appwrite's permission model is organized around documents, collections and teams, so each RLS policy has to be translated into an equivalent permission rule or moved into a server-side function. Tenant boundaries must be tested as carefully as the data itself, because a mistake in the translation can expose one tenant's rows to another.
- Policy translation: Inventory every RLS policy and map it to Appwrite permissions or to server-side checks, then test each tenant boundary with separate accounts.
- Postgres-specific logic: Stored procedures, triggers, views and extensions need review, since they do not move as-is into Appwrite's database layer.
- Edge Functions: Rewrite each function for an Appwrite Functions runtime and check its outbound calls, secrets and scheduling.
- Data volume and partitioning: Plan the import in batches with resumable checkpoints, and verify row counts per tenant after each batch.
- Realtime and per-tenant limits: Confirm how realtime subscriptions and per-tenant usage behave under load before cutover.
Before planning, ask for a complete list of RLS policies, functions and database objects, and confirm which of them Appwrite can express natively.
A regulated workload has the same technical steps as the other profiles but adds evidence requirements. The organization must show where data lives, who accessed it, how migrated records were verified, and how the target platform is operated. Residency is decided early: Supabase Cloud projects sit in one chosen region, and the target choice (Appwrite Cloud region, or a self-hosted deployment in your own data center or cloud account) determines where users, rows and files end up. Auth and data flows need documented sign-off because they often touch third-party services.
- Residency decisions: Record where Supabase data is hosted today and where the Appwrite target will run before any data moves.
- Migration evidence: Keep reconciliation reports for users, rows and files, plus hash handling records, as inputs to your own change records.
- Operations ownership: Self-hosted Appwrite runs its built-in datastores on a single replica without failover, so production designs need managed databases or operators, and the team must own backups and restore tests.
- Logging and access control: Define who can use the Console and API keys, and where audit logs are retained.
- Assessment support: Independent auditors and certification bodies issue any attestation, so confirm the evidence they expect with them early.
Before starting, ask your compliance lead which controls the migration must evidence and confirm with Appwrite which deployment model covers that residency requirement.
Questions teams ask before moving from Supabase to Appwrite
How much effort does a move from Supabase Cloud to Appwrite take?
The effort depends mainly on how much of your application is tied to Supabase-specific features, not on the size of the data alone. Appwrite Migrations can import users, databases and files from a Supabase project, but row data moves only partially and functions do not move at all, so the work concentrates on the parts you rebuild. Teams with a small schema, few Edge Functions and simple row-level access usually have less to redesign than teams whose logic lives in Postgres policies, triggers and SQL functions. Ask any provider for a written inventory of your tables, policies, functions, auth providers and storage buckets before agreeing on scope, because that inventory is what turns a vague estimate into a fixed plan.
Can Appwrite Migrations move Supabase users without forcing password resets?
Appwrite's Users API accepts imported password hashes including bcrypt, Argon2, MD5, PHPass, Scrypt, Scrypt modified and several SHA variants, so users whose hashes fall into one of these types can often keep their passwords. Whether a specific account keeps its password depends on the hash type and parameters your Supabase project stores, which you should verify with a test import before cut-over. Accounts with unsupported or missing hashes, and any social or SSO identities, need a separate plan such as a reset flow or re-linking at first sign-in. Confirm the hash format in your export and the current Users API reference before promising users a seamless login.
Do Edge Functions and RLS policies move to Appwrite automatically?
No. Appwrite Migrations does not move Supabase Edge Functions, so each function needs to be rewritten as an Appwrite Function that runs on the Open Runtimes executor, with its own triggers, environment variables and dependencies. Row Level Security policies are Postgres-specific and do not transfer as-is; the access rules must be expressed with Appwrite's permissions model on each collection or table and checked again with test accounts. Any SQL functions, triggers, extensions or realtime subscriptions that rely on Postgres behavior also need explicit redesign. Treat this as the largest source of engineering work and verify each rule with automated tests before traffic moves.
How long should a parallel run last, and what does it need?
Length is set by your own acceptance tests, not by a fixed period published by either vendor, so agree the exit criteria before the run starts. A parallel run needs two environments kept in step: the Supabase project remains the source of truth while the Appwrite target receives imported users, data and files, with a repeatable sync or re-import process. You also need monitoring on both sides, a rollback path for writes made during the overlap, and a named owner who signs off on login, data integrity and function behavior. Ask your provider how they plan to handle writes that land during the overlap, since that decides whether the run can end cleanly.
Which Appwrite target should we run: self-hosted or Appwrite Cloud?
The choice turns on operating responsibility, data location and how much database resilience you need to build yourself. Appwrite publishes a Docker installation path that requires at least 2 CPU cores, 4 GB of RAM, 2 GB of swap and Docker Compose version 2, and its Helm chart runs the built-in PostgreSQL, Redis, ClickHouse and object storage as single replicas without failover. That means production self-hosting normally needs managed datastores or operators, backups you test, and monitoring you own. Appwrite Cloud moves hosting, but its Free plan pauses projects after a period of inactivity and freezes at resource limits, while Pro projects continue with overage charges, so review those limits against your load. Ask for a written comparison of both targets against your data residency and support needs.
Can our own team do the migration without outside help?
A team can do the migration in-house if it has someone who has run Postgres-backed services in production, someone who can rewrite Supabase policies and functions in Appwrite's model, and time to test auth, data and storage end to end. The work requires access to the Supabase project with owner rights, a staging Appwrite environment you can rebuild, a security review of permissions, and a cut-over plan that covers DNS, client app releases and mobile users on older builds. Teams without that mix often use a fixed-scope implementation partner for the migration plan, the rewrite, the hardening and the parallel run, while keeping day-to-day operation in-house. DeployOpen plans and implements self-hosted open-source platforms in your own infrastructure under a written scope, and can also run security testing against the result if that is part of the engagement.
Decommissioning Supabase Cloud without losing data
Do not delete the Supabase Cloud project until you have a verified, complete copy of everything it holds and a record that the copy matches the source. Run a final export of the Postgres schema and data, the users and their auth records, and every Storage bucket, then compare row counts per table, object counts and checksums against the live project on the day of cutover. Keep the export files in your own storage with access restricted to the migration team, and log who ran each step. Because the migration moves users and rows through Appwrite Migrations and re-creates functions by hand, the verification step is the point where you confirm that nothing was silently skipped, particularly rows you expected to be transformed and functions that were never moved.
Keep the Supabase Cloud project and its backups for the retention period your organization agrees in writing before deletion, and do not treat a successful import as the end of that period. Confirm with Supabase's documentation for your specific plan what happens to backups, daily or otherwise, when a project is deleted, whether a deletion can be undone, and how long any recovery window lasts. Ask the vendor directly if the documentation does not answer these questions for your plan. Before you delete, rotate or revoke the project's API keys and service role keys, then remove the Supabase URL and key references from client apps, mobile builds, CI variables, cron jobs, webhooks and third-party services. Search your repositories and configuration for the old project hostname, since a stale reference will keep failing quietly after the project is gone.
Confirm that no integration still sends traffic to the old endpoints before you delete anything. Check analytics and gateway logs for requests to the Supabase hostname over a full business cycle, including any monthly or quarterly jobs, and review email templates, OAuth redirect URIs, webhook targets and partner callbacks that were configured against the old project. Plan a short window in which both systems are reachable, and record the sign-off from the owners of each integration. Once the logs show no traffic and the retention period has closed, delete the project and record the date and the person who approved it, so the decommissioning is itself auditable.

