Migrate from Firebase to Appwrite: what moves and what you rebuild
Appwrite has a built-in Firebase migration that covers users, Firestore data and files, while Cloud Functions, nested Firestore data and OAuth sessions need manual work, and Realtime Database is not imported at all. If your renewal, Blaze billing, data residency or lock-in concern is pushing you toward self-hosting, plan for the import to be the smaller part of the project. The harder work is rebuilding server code, reshaping data and reconfiguring access. The migration runs from the Appwrite Console under Project Settings > Migrations, using a Google Cloud service account JSON key that holds the Firebase Viewer and Identity Toolkit Viewer roles. Grant only those roles, and confirm the key's scope with your cloud security team before you create it.
Usually an internal platform or backend team carries this work, sometimes with an implementation partner for the hardening and cutover. Appwrite's migrations overview marks Firebase users, databases and files as migrated, rows as partial and functions as manual, so inventory your Firestore subcollections, Realtime Database paths and Cloud Functions early. Subcollections are not migrated automatically, so each one needs a flattening decision. Functions must be rewritten because of syntax and runtime differences. Ask your team to estimate effort from that inventory rather than from the import itself, and confirm the current Appwrite and Firebase behavior in a test project before you commit to a timeline.
Plan for three post-import tasks. First, add Web, Flutter, Android and iOS apps as platforms, because Appwrite rejects requests from unknown apps. Second, add permissions to every migrated collection, bucket and file, since imported resources do not carry your Firebase security rules forward. Third, test sign-in with the imported password hashes. Appwrite's Users API accepts Scrypt modified hashes through POST /users/scrypt-modified, but confirm that a sample of real accounts signs in before cutover. Users who signed in with Google, Apple or other OAuth providers will need to re-authenticate, since their sessions remain with the provider.
Which Firebase capabilities map cleanly to Appwrite
This table maps each Firebase capability on the migration path to its Appwrite counterpart and marks it as clean, needs rework or gap. Read the rows with the migration limits in mind: the Firebase importer covers Auth users, Firestore data and files, while Realtime Database, subcollections, OAuth sessions and Cloud Functions need separate work. Treat the last column as the planning checklist for the cutover.
| Firebase capability | Appwrite counterpart | Status and what to plan |
|---|---|---|
| Firebase Authentication | Appwrite Auth | Needs rework: users and scrypt modified hashes import, but OAuth users are not moved and their sessions must be re-linked with each provider |
| Cloud Firestore | Appwrite Databases | Needs rework: top-level collections migrate, but subcollections are not migrated automatically and documents must be remodeled as rows |
| Cloud Firestore document shapes | Appwrite 2.0 relational tables on PostgreSQL | Needs rework: Appwrite 2.0 provisions PostgreSQL by default, so nested document shapes need relational modeling or DocumentsDB |
| Schemaless JSON documents | DocumentsDB (disabled by default) | Needs rework: ships disabled and needs PostgreSQL and MongoDB engines a stock install does not deploy, so confirm the engine setup first |
| Cloud Storage for Firebase | Appwrite Storage | Clean: the importer moves files, but confirm bucket permissions are added after import |
| Realtime Database | Appwrite Realtime | Gap: the Firebase importer does not support Realtime Database, so data and listeners must be exported and rebuilt |
| Cloud Functions for Firebase | Appwrite Functions | Gap: functions are marked manual and must be rewritten for Appwrite's runtime and syntax differences |
| Firebase Hosting | Appwrite Sites | Needs rework: hosting is not part of the import, so redeploy the web build and configure domains and redirects |
| Firebase Extensions | Functions or hooks | Gap: no direct equivalent, so inventory each extension and rebuild its behavior as an Appwrite function |
What data and integrations to move, and by which documented path
A Firebase to Appwrite move splits into four data sets and a list of integrations that the migration tooling does not carry over. Each one has its own documented path, its own permissions and its own check before cutover. Treat the Console import as one step in a longer plan, not the whole move.
Auth users and password hashes
Appwrite's Users API accepts Scrypt modified hashes through POST /users/scrypt-modified, the scrypt variant Firebase Auth uses by default. Export users with the Firebase CLI so the hash parameters travel with each record. Before cutover, sign in with a test account whose password was never reset to confirm the hash verifies. Accounts from OAuth providers are not carried over and need their own plan.
Service account roles for the import
The Console migration under Project Settings > Migrations needs a Google Cloud service account JSON key. Grant it the Firebase Viewer and Identity Toolkit Viewer roles, and no broader project role. Keep the key only for the migration window, then delete it and rotate any copy stored in CI or a shared drive. Confirm the role names in your own Google Cloud project before the run, since console labels can differ.
Firestore collections and nested data
The Console migration reads Firestore only, and Appwrite's migrations overview marks rows as partially migrated. Subcollections are not pulled in automatically, so list every nested path in your data model and load each one separately. Check document counts per collection after the import and compare field types, since timestamps, references and arrays need a deliberate mapping into Appwrite databases.
Storage files and access rules
Appwrite's migrations overview marks files as migrated, but file permissions do not map one to one from Cloud Storage security rules. Rebuild bucket permissions in Appwrite after the copy and test a read by an unauthorized user. Confirm that file IDs and download URLs used by your clients still resolve, because stored links from the Firebase domain will break.
Realtime Database JSON tree
Appwrite's Firebase migration does not support Firebase Realtime Database as a source. Export the JSON tree with the Firebase CLI or console, then write a transform that flattens each branch into a table or collection with explicit keys. Plan the subscription change from path listeners to Appwrite Realtime channels, and load a copy into a staging project to test ordering and write volume.
Client SDKs, hosting rewrites and provider re-linking
Appwrite rejects requests from apps that are not registered, so add the Web, Flutter, Android and iOS platforms after import. Replace Firebase SDK calls, update Firebase Hosting rewrites that call functions, and re-link third-party sign-in providers such as Google or Apple with new client IDs and redirect URIs. Functions must be rebuilt by hand because the runtimes differ, so list each function before cutover.
Migration sequence from inventory to decommission
This sequence moves a Firebase project to a self-hosted Appwrite instance in controlled stages, so each phase produces evidence that the data, users and clients behave correctly before Firebase is switched off. Each step closes with a named output that the next step depends on.
Inventory collections, users, functions and extensions
Your team lists every Firestore collection and its subcollections, every Firebase Auth user and sign-in provider, every Cloud Function, every Realtime Database path and every Cloud Storage bucket, plus any installed Firebase Extensions. Mark which items Appwrite's Firebase migration moves (users, Firestore data, files), which are partial (nested rows such as subcollections) and which must be rebuilt by hand (Cloud Functions, OAuth sessions, Realtime Database data). The output is a written inventory with an owner and a disposition for each item, and it is the baseline for every count you reconcile later.
Build a pilot project on Appwrite
Provision a self-hosted Appwrite instance using the installation guide, then create a pilot project and run the Firebase migration from the Console under Project Settings > Migrations. Create a Google Cloud service account JSON key with the Firebase Viewer and Identity Toolkit Viewer roles, and use a copy of the Firestore data and Auth users rather than production. Your platform engineer and a backend developer run the import and log every error. The output is a pilot project with imported collections and users, and a list of documents and nested records that did not arrive as expected.
Rebuild nested data, functions and auth flows
Using the pilot results, your backend developers remodel subcollections as separate Appwrite tables or relationships, and rewrite each Cloud Function in the Appwrite Functions runtime, since syntax and runtime differences mean they cannot be moved as is. Auth owners confirm which OAuth users must sign in again because their sessions are managed by the third-party provider. The output is a rebuilt function list with tests passing against the pilot data, and a sign-in test matrix covering each provider.
Register client platforms and set permissions
After import, add each Web, Flutter, Android and iOS app as a platform in the Appwrite project, because Appwrite rejects requests from unknown apps. Then add permissions to every migrated database, collection, bucket and function so that clients can read and write only what they should. A security engineer reviews the permission model and tests it with a user from each role. The output is a registered platform list for each client and a permission review record with test results.
Run a parallel period with reconciliation
Keep Firebase live while the production data is copied to Appwrite, and run a reconciliation job that compares user counts and document counts per collection between the two systems on a fixed schedule agreed in your runbook. Investigate every difference until the cause is known, whether it is a nested record, a rejected write or a sign-in path. The output is a signed reconciliation report showing matched counts for each collection and user group, with each exception explained and closed.
Cut over client apps
Release client builds that point at the Appwrite endpoint and the new project ID, then move traffic in the order your runbook specifies, with the Firebase project set to read-only where your data model allows it. Keep a documented rollback path to Firebase until the reconciliation shows no open exceptions. The output is a cutover record listing each client version released, the time of each switch and confirmation that new writes land only in Appwrite.
Archive exports and decommission Firebase
Before deleting anything, export Firestore, Auth users with their password hashes and scrypt parameters, and Cloud Storage files, and store the archives under your retention policy. Confirm that the archives can be read, then disable or delete the Firebase resources that are no longer needed and remove deployed Firebase Extensions. The output is a verified archive set with checksums, an access list for it, and a signed decommission record that names what was removed and when.
What drives migration cost and duration
This table breaks the Firebase-to-Appwrite move into its cost components, showing who is paid for each, whether it is one-time or recurring, and what pushes it up or down. Read it as a checklist for scoping and for comparing quotes, since the largest variable is usually how much of the Firestore data model and Cloud Functions code must be redesigned by hand.
| Cost component | Who is paid or who spends effort | One-time or recurring | What drives it |
|---|---|---|---|
| Internal staff time | Your engineers, product owners and security reviewers | One-time, plus ongoing reviews | Number of apps and SDK clients, team familiarity with Appwrite, and how many decisions need sign-off |
| Data model redesign | Implementation partner or in-house engineers | One-time | Nested subcollections and document shapes that Appwrite does not migrate automatically, and how many rows must be reshaped into Appwrite collections |
| Cloud Functions rebuild | Developers who rewrite functions for Appwrite Functions | One-time | Number of functions, triggers, runtime differences and syntax changes, and any Firebase Extensions that must be replaced |
| Client SDK changes | App developers across Web, Flutter, Android and iOS | One-time per client | Each platform must be added in the Appwrite Console and its SDK calls rewritten, so the number of shipped apps sets the effort |
| Auth and OAuth re-linking | Identity and app teams | One-time | OAuth users are not moved and must sign in again, so the user base and support load for re-login drive the cost |
| Self-hosted infrastructure | Your cloud team or a hosting provider, plus cloud bills | Recurring | Minimum of 2 CPU cores, 4 GB RAM and 2 GB swap per the installation guide, plus production capacity; production should use managed or operated datastores because built-in ones run a single replica |
| Operations and patching | Platform or SRE team | Recurring | Frequency of Appwrite releases (2.0 on September 4, 2026 and 2.5.0 on October 13, 2026 per GitHub), upgrade testing and backup ownership |
| Testing and cutover | QA, security testing and the business owners of the data | One-time | Volume of migrated users and records to verify, password-hash login tests, and whether a parallel run with Firebase is needed |
What usually goes wrong and how to prevent it
Most Firebase-to-Appwrite migrations fail quietly rather than loudly: data is missing, requests are refused, or permissions are wrong on the first day. The cards below cover the risks that recur across the import, the platform setup and the operation of a self-hosted 2.x stack, each with a check to run before cutover.
Silent loss of nested data
Appwrite's Firebase migration moves Firestore collections but does not migrate nested rows such as subcollections automatically. A migration can report success while child documents are absent, so the nested records look fine in a count of top-level documents and are missing in the app. Before cutover, list every subcollection in the Firebase project, record document counts for each path, and compare those counts with the rows in Appwrite. Agree in writing who owns the reconciliation.
Requests rejected for unregistered apps
Appwrite rejects requests from apps it does not know, so a migrated project can look broken even when its data and users are correct. Web, Flutter, Android and iOS clients each need to be added as platforms in the project settings, using the same bundle IDs, package names and hostnames the production apps use. Test each client build against the new endpoint in a staging project before the switch, and keep a checklist of every app identifier.
Permissions left open or closed
Imported resources do not carry over working access rules from Firebase Security Rules, so teams either leave collections readable by everyone or discover that legitimate reads fail. Both outcomes are common after import. Define permissions for each migrated database, collection, bucket and function before any client reaches the endpoint, then test each role (anonymous, signed-in user, admin) with real requests. Treat any collection still open to all users as a release blocker.
Password hash and sign-in mismatches
Users imported with Scrypt modified hashes can sign in without a reset only if the hash and its parameters are exported and imported intact. A truncated export, a missing parameter or a user who signed in with Google or another OAuth provider will fail in a way that looks like a wrong password. Export a sample of Auth users with the Firebase CLI, import them into a test project, and sign in with known accounts. Count the OAuth-only users separately, since their sessions stay with the provider and they must re-link.
Single-replica datastores in production
The built-in PostgreSQL, Redis, ClickHouse and object storage in Appwrite's Helm chart run a single replica without replication or failover. A pod or node failure can make the application unavailable or lose data that was not backed up. Before go-live, decide which components move to managed services or operators with replication, set up tested backups and restores, and document the recovery time your organization needs. Ask the implementation partner to show a restore, not only a backup job.
Fast-moving 2.x release line
Appwrite 2.0 replaced the engine underneath the platform and rebuilt the Console, and the project has since shipped 2.5.0 on October 13, 2026. Existing 1.9.x installs need one upgrade command and a migration, and the older 1.9 line received a maintenance release on October 8, 2026. Pin the image tag, read each release note before upgrading, rehearse the upgrade on a copy of production data, and schedule a recurring review so security patches are not missed.
How the migration differs by starting point
A small app with a few collections and a modest user base has the narrowest migration. The main work is confirming that the Firestore collections are flat enough for Appwrite's Firestore import, moving the users with their password hashes, and rebuilding a handful of functions by hand. Because the data volume is small, the import itself is usually the least demanding step, and most of the effort goes into the client SDK change and the permission model.
- Collection shape: Confirm that documents sit at the top level. Appwrite does not migrate subcollections automatically, so any nested data needs a planned mapping.
- Users: Check whether users sign in with email and password, which keeps the Scrypt modified hash path open, or with OAuth providers, which must be re-linked.
- Functions: List each Cloud Function and decide whether it is rebuilt in Appwrite Functions or removed.
- Platforms: Register every Web, Flutter, Android and iOS app in the new project, or requests will be rejected.
- Permissions: Add permissions to each migrated collection and bucket, since imported resources do not inherit the old Firestore security rules.
Ask the Appwrite or DeployOpen team to confirm the import behavior against a copy of your own export before you commit to a cutover date.
A production app with heavy Firestore use and subcollections needs a deeper inventory. Subcollections are not migrated automatically, so each one has to be flattened into a separate table or collection with a reference field, and the application code that reads them must be rewritten. Write-heavy workloads also need a plan for keeping Firestore and Appwrite in step during a cutover window, because data written after the export will not appear in the new project unless it is copied again.
- Subcollection map: Document each parent-child path and the queries that depend on it before any data moves.
- Delta sync: Decide how writes made after the initial export are captured and replayed.
- Database engine: Choose between PostgreSQL, MariaDB and MongoDB for new installs, and confirm which engine fits your query patterns.
- Operations: The Helm chart documentation says built-in datastores run a single replica without failover, so production data should use managed services or operators.
- Rollback: Keep the Firebase project readable until the new stack has passed acceptance tests.
Confirm with your team how much write traffic lands during the cutover window, since that drives the sync design more than the total data size does.
A team that uses the Firebase Realtime Database cannot rely on the Firestore importer, because Appwrite's Firebase migration supports only Firestore as a database source. The Realtime Database holds a JSON tree, so its contents must be exported separately, reshaped into collections or tables, and loaded by a custom script or by hand. This is the largest change in scope, since the data model and the listener code both change.
- Export: Take JSON backups of each Realtime Database instance and record the path structure.
- Data model: Map each top-level branch to a collection and decide how nested keys become documents or relationship fields.
- Listeners: Rewrite each subscription against Appwrite Realtime, which works on the resources you define rather than on tree paths.
- Custom import: Budget for a script that writes through the Appwrite server SDK, and test it on a sample export first.
- Consistency: Confirm that the reshaped data keeps the same identifiers that clients and other systems already reference.
Before planning the work, confirm the exact Realtime Database layout with the team that owns it, since undocumented paths are the most common source of missing data.
A team that needs EU residency has a different reason to migrate, and the scope changes around where each service runs. Firebase Authentication processes data only in the United States, and Cloud Firestore locations cannot be changed after provisioning. Appwrite can be self-hosted in an EU data center, so auth, data and files can stay in one jurisdiction, but that only holds if every component of the stack is deployed there, including backups, logs and any object storage.
- Location audit: List where each Firebase service stores data today, including Authentication, Storage and any backups.
- Target placement: Deploy the Appwrite stack, object storage and backups in EU infrastructure you control.
- Support access: Document who outside the EU can reach the systems during operations or support sessions.
- Telemetry: Check what logs, metrics and crash reports leave the environment and where they are sent.
- Evidence: Record the data flows so an auditor or data protection officer can trace them.
Ask your legal or compliance team to define what residency means for your contracts, and confirm the deployment details with Appwrite, since the facts here do not establish a specific EU data center configuration.
Questions teams ask before migrating from Firebase to Appwrite
Can our own engineers run the Firebase to Appwrite migration in-house?
Yes, a team with Google Cloud and Appwrite experience can run the import itself, because the import is driven from the Appwrite Console under Project Settings > Migrations. The harder work sits outside the import: mapping nested Firestore data, rebuilding Cloud Functions, adding platforms and permissions, and testing login with migrated users. Ask whether your team has someone who has done a Firestore schema redesign before. DeployOpen plans, implements and tests this work under a fixed written scope if you prefer to hand it over, and the Appwrite Firebase migration docs list the steps your engineers would follow.
What drives the cost and effort of moving from Firebase to Appwrite?
The cost is driven mainly by how much of your data model and code must be rebuilt by hand, not by the import itself. The main drivers are the number of Firestore subcollections that need flattening, the number and complexity of Cloud Functions, how many sign-in providers you use (OAuth users are not migrated), and the size of the test matrix across Web, Flutter, Android and iOS apps. Infrastructure is a recurring cost you pay to run the stack, and staff time to operate and patch it is recurring too. Ask any quote to split one-time migration work from ongoing operations, and to name each Firebase service in scope.
How long does a Firebase to Appwrite migration typically take?
The duration depends on the scope you agree, and no fixed timeline applies to every project. The biggest factors are how many Firestore collections need nested data reshaped, how many Cloud Functions must be rewritten, whether you can run old and new systems in parallel during cutover, and how much of your user base must test sign-in. Appwrite's migrations overview marks Firebase users, databases and files as migrated, rows as partial and functions as manual, so manual work sets the critical path. Ask for a written plan that lists each phase and its acceptance test before work starts.
Do Firebase password hashes move to Appwrite without forcing resets?
Yes, in most cases, because Appwrite's Users API accepts Scrypt modified password hashes, the scrypt variant Firebase Auth uses by default. The Firebase CLI exports hashes along with the project's scrypt parameters, which you need during import. Confirm that your export includes the hash and salt for every user, and test a sample login before cutover. Users who signed in with OAuth providers such as Google or Apple do not carry a password, and their sessions are not migrated, so plan to re-link those accounts. See the Firebase auth export reference and the Appwrite Users API reference for the exact parameters.
What happens to our Cloud Functions during the move to Appwrite?
Cloud Functions are not migrated automatically and must be rebuilt by hand, because the syntax, runtime and trigger model differ between Firebase and Appwrite Functions, which run on Open Runtimes. Start with an inventory that lists each function, its trigger (HTTP, Firestore write, Auth event or scheduled), its dependencies and the secrets it reads. Then decide which functions move to Appwrite Functions, which become client-side logic and which are retired. Appwrite's migrations overview marks functions as manual, so budget engineering time for each one and test triggers against migrated data.
Which data does Appwrite's Firebase import leave behind?
The import covers Firestore only, so Firebase Realtime Database content, nested subcollection rows and OAuth sessions must be handled separately. Appwrite's Firebase migration does not move Realtime Database data, and nested rows such as subcollections are not migrated automatically, so you need to flatten or relate them into Appwrite collections yourself. Export Realtime Database data as JSON before shutdown, and map each subcollection to its own table or collection with the parent ID stored as a field. Check the Appwrite Firebase migration docs for the current list of supported sources before you commit to a plan.
What must our team provide before an Appwrite migration can start?
Your team must provide a Google Cloud service account JSON key with the Firebase Viewer and Identity Toolkit Viewer roles, access to the Appwrite Console for the target project, and a named owner who signs off on the data mapping. You also need a target environment that meets Appwrite's installation requirements, which include 2 CPU cores, 4 GB of RAM, 2 GB of swap and Docker Compose version 2 for a single-host install. For production, plan a managed or operator-run PostgreSQL, Redis and object storage, because the built-in datastores run a single replica without failover. Confirm the exact requirements in the Appwrite self-hosting installation guide.
Does Appwrite need to be on a supported version before we migrate?
Yes, you should target a current Appwrite release line, because releases change often and the install and upgrade path differs between lines. Appwrite 2.0 arrived on September 4, 2026, and new installs provision PostgreSQL by default, while existing 1.9.x installs upgrade with one command and a migration. Check the Appwrite 2.0.0 release notes before choosing a version, and pin the image tag you test with so production matches what you validated. Ask your implementation partner which release line the plan assumes.
How DeployOpen scopes and runs a Firebase to Appwrite migration
DeployOpen is a Chainscore Labs company that plans, implements, integrates, hardens, backs up and documents self-hosted open-source platforms inside the client's own infrastructure, including the cloud accounts, data centers or air-gapped networks where the Appwrite stack will run. For a Firebase to Appwrite move, that work starts with a written scope that names the Firestore databases, Auth user sets, Storage buckets and Cloud Functions in play, the target Appwrite version and the hosting model. Most engagements are fixed-scope, so deliverables and timelines are agreed in writing before any migration work begins. Ask any provider to put the excluded items in writing too, such as Realtime Database data, subcollections and functions that must be rebuilt by hand.
Delivery usually follows the same sequence whatever the size of the app: stand up the Appwrite platform, run a rehearsal import against a copy of the Firebase data, verify users can sign in with their existing hashes, then register the Web, Flutter, Android and iOS platforms and set permissions on each migrated resource before cutover. Each step produces evidence the client keeps, such as import logs, sign-in test results, backup records and configuration exports. DeployOpen can also prepare systems, controls and evidence for a compliance assessment, but it does not issue audit reports, attestations or certifications. Independent auditors and certification bodies make those decisions, so confirm early which evidence your assessor expects.
After cutover, the stack needs an owner. Ongoing support, upgrades and continuous testing are available as retainers, which suit teams that do not want to patch Appwrite releases or maintain backups on their own. Ask for a clear split of responsibilities in the proposal: who operates the database and object storage, who applies Appwrite upgrades, who runs restore tests and who responds to incidents. Confirm these points with the provider and against your own environment rather than assuming them, especially where the Helm chart's built-in datastores run without replication.

