SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

Firebase alternatives you can self-host

Firebase Studio shuts down in March 2027 but Firestore stays. Compare PocketBase, Parse, Supabase and Appwrite by what each costs to run on a VPS.

Leaving Firebase is a choice, not an eviction

Firebase alternatives you can self-host exist for every backend feature except two, and you have more time to choose than the headlines suggest. Firebase Studio, the browser IDE, entered its shutdown phase on 2026-03-19 and stopped creating new workspaces on 2026-06-22. It shuts down for good on 2027-03-22. That is the only thing being retired. Google's own migration page says Cloud Firestore, Authentication, App Hosting, Cloud Storage, Cloud Functions and the Realtime Database are not affected, and that databases and user data will continue to work normally (verified on 2026-09-19).

So if your app runs on Firestore, nothing is being taken from you. Moving is a decision you make about cost and control, and it deserves a real comparison. Below are the four backends a person can run on a single VPS, ranked by what they cost to operate: the number of processes you keep alive and the RAM the project's own docs ask for. After that comes a feature map from Firebase to each backend, and an honest list of what has no drop-in, including who should stay.

What a self-hosted Firebase alternative gives you

Firebase is a BaaS (backend as a service): a database, user accounts, file storage, server-side functions and realtime updates, all behind one client SDK, with Google running the servers. A self-hosted alternative gives you the same shape of product on a machine you rent. The trade is plain. You gain a fixed monthly bill and data that lives where you can see it. You take on backups, TLS (transport layer security) certificates, upgrades and the restart at 3 a.m. Every project below can be run by one person, but they differ a great deal in how much of that person's time they need.

The four backends ranked by what they cost to run

Operating cost on a VPS comes down to two numbers that are easy to measure: how many long-running processes you supervise, and how much memory they want before your own app gets any. The counts below come from each project's release assets or compose file at a pinned version, checked on 2026-09-19. Where a project publishes no figure, the chart says so instead of guessing.

ChartProcesses started by default, and declared, at a pinned release
The data behind this chart
[
  {
    "tool": "PocketBase v0.40.4",
    "started": 1,
    "declared": 1,
    "notes": "One Go binary, one process; releases page, 2026-09-19"
  },
  {
    "tool": "Parse Server 8.6.91",
    "started": 2,
    "declared": 2,
    "notes": "parse-server plus mongod or postgres; README and Docker Hub, 2026-09-19"
  },
  {
    "tool": "Supabase self-hosted/v0.8.1",
    "started": 11,
    "declared": 11,
    "notes": "docker/docker-compose.yml at the ref the Docker guide pins, 2026-09-19"
  },
  {
    "tool": "Appwrite 2.2.0",
    "started": 19,
    "declared": 39,
    "notes": "docker-compose.yml at tag 2.2.0; 20 services sit behind compose profiles, 2026-09-19"
  }
]

PocketBase is 1 process. Parse Server is 2, and one of the two is a database engine you administer yourself. Self-hosted Supabase starts 11 containers from its compose file at the ref its docs pin today. Appwrite's compose file at tag 2.2.0 declares 39 services; 19 of them start on a plain docker compose up -d and the rest sit behind compose profiles. Three of those 19 are database engines, because the repository file is the developers' file, and the installer wizard writes a shorter one with a single database. Count the file you actually received before trusting any number, including this one:

docker compose config --services | wc -l
docker compose ps -q | wc -l

The first line counts what the file declares. The second counts what is running now.

ChartRAM named in each project's own docs, September 2026
The data behind this chart
[
  {
    "tool": "PocketBase",
    "ram_gb": 4,
    "cpu_cores": 2,
    "notes": "FAQ example box: a 2 vCPU, 4 GB Hetzner CAX11 serving 10,000+ realtime connections; not a stated minimum"
  },
  {
    "tool": "Supabase",
    "ram_gb": 4,
    "cpu_cores": 2,
    "notes": "Stated minimum in the Docker self-hosting guide; 8 GB or more and 4 cores or more recommended"
  },
  {
    "tool": "Appwrite",
    "ram_gb": 4,
    "cpu_cores": 2,
    "notes": "Stated minimum in the installation guide, with 2 GB of swap"
  }
]

The three projects that publish a memory figure all name 4 GB on 2 cores. Read the notes column, because the figures mean different things. Appwrite and Supabase state 4 GB as a minimum, and Supabase recommends 8 GB or more for anything past development. PocketBase's FAQ describes a 2 vCPU, 4 GB box serving more than 10,000 realtime connections, which is a capacity claim and not a floor, and the project publishes no minimum. Parse Server's README names no memory figure at all, so size it by the database under it. Sizing a VPS by workload covers how to turn these numbers into a plan.

PocketBase: one Go binary and SQLite

PocketBase is a single executable written in Go. It embeds SQLite, a realtime subscription API, user management with OAuth2 providers, file storage on local disk or S3, and an admin dashboard. There is no Docker to install and nothing else to supervise. The release zip is about 12 MB and holds one binary.

Install it under a system user. The version is pinned to v0.40.4, released 2026-09-12, so what you download does not change under you.

sudo apt update && sudo apt install -y curl unzip
sudo useradd --system --home /opt/pocketbase --shell /usr/sbin/nologin pocketbase
sudo install -d -o pocketbase -g pocketbase /opt/pocketbase
cd /tmp
curl -fsSLO https://github.com/pocketbase/pocketbase/releases/download/v0.40.4/pocketbase_0.40.4_linux_amd64.zip
sudo unzip -o pocketbase_0.40.4_linux_amd64.zip pocketbase -d /opt/pocketbase
sudo chown pocketbase:pocketbase /opt/pocketbase/pocketbase
cd /opt/pocketbase && sudo -u pocketbase ./pocketbase superuser create admin@example.com 'a-long-random-password'

The last line creates the first dashboard account without a browser. It also creates pb_data/ next to the binary, owned by the service user, which is where the SQLite files and every uploaded file live.

Now the unit file, /etc/systemd/system/pocketbase.service:

[Unit]
Description=PocketBase
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pocketbase
Group=pocketbase
WorkingDirectory=/opt/pocketbase
ExecStart=/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090
LimitNOFILE=4096
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now pocketbase
curl -s http://127.0.0.1:8090/api/health

The health call should return a JSON body containing "code":200. The dashboard is at /_/ and the API under /api/. This unit binds to localhost only, so put nginx or Caddy in front for TLS. PocketBase can also do TLS itself: pocketbase serve yourdomain.com obtains a Let's Encrypt certificate and listens on 80 and 443, which a non-root user may not bind. The docs' answer is sudo setcap 'cap_net_bind_service=+ep' /opt/pocketbase/pocketbase, run again after every binary upgrade, because replacing the file drops the capability.

Two things to know before you commit. First, the README states that full backward compatibility is not guaranteed before v1.0.0, so read the release notes before each upgrade instead of swapping the binary blind. Second, the FAQ is explicit that PocketBase scales on a single server only, vertically. That is a feature for most projects and a hard limit for a few. SQLite handles far more than people expect, and SQLite in production on a VPS shows where it stops. Back up by copying pb_data/ while the service is stopped, or use the Backups page in the dashboard settings.

Parse Server: Node plus MongoDB or Postgres

Parse Server is the open-source continuation of Parse, the BaaS Facebook shut down in 2017. It is a Node.js application that stores classes of objects in MongoDB or PostgreSQL, with users, sessions, OAuth adapters, file storage, push notification adapters for APNs and FCM, LiveQuery for realtime, and Cloud Code for server-side functions that run inside the same process. Its README, checked 2026-09-19, lists Node.js 22 and 24, with MongoDB 7 and 8 or Postgres 16 through 18, in a table that says which Parse major version each pairs with.

Ubuntu 24.04's packaged Node is older than that table allows, so the least fragile route on a VPS is the official image, pinned to the release current on 2026-09-13:

docker network create parse
docker run -d --name parse-mongo --network parse \
  -v parse-mongo:/data/db mongo:8.0
docker run -d --name parse-server --network parse \
  -p 127.0.0.1:1337:1337 parseplatform/parse-server:8.6.91 \
  --appId APPLICATION_ID --masterKey MASTER_KEY \
  --databaseURI mongodb://parse-mongo/parse

Replace both keys with long random strings. The master key bypasses every permission check on every object, so it never goes into a client app. Test that the server answers:

curl -s -X POST http://127.0.0.1:1337/parse/classes/GameScore \
  -H 'X-Parse-Application-Id: APPLICATION_ID' \
  -H 'Content-Type: application/json' \
  -d '{"score": 1337, "playerName": "Sean Plott"}'

A healthy reply is a small JSON object holding objectId and createdAt. A reply containing unauthorized means the application id header does not match --appId. The admin UI is a separate package, Parse Dashboard, and the reverse proxy for TLS is yours to add. Two processes is the smallest footprint after PocketBase, but one of them is a database that needs its own backups and its own upgrade path, and MongoDB's memory use grows with the data set. If you would rather run Postgres, Parse supports it, and managed Postgres versus running it on your VPS is the decision to make first.

Self-hosted Supabase: Postgres and eleven containers

Supabase is Postgres with a set of services around it: PostgREST for the REST API, GoTrue for auth, a storage API, a realtime server, an edge function runtime built on Deno, a connection pooler, and a dashboard. The Docker self-hosting guide, read on 2026-09-19, pins the ref self-hosted/v0.8.1, and its compose file at that ref defines 11 services. The gateway in that file is Envoy. Older copies of the guide used Kong, so do not mix instructions from two versions.

The hardware line in the same guide is the clearest of any project here. The minimum is 4 GB RAM with 2 CPU cores on a 40 GB SSD. The recommendation for development and medium production loads is 8 GB or more with 4 cores or more on 80 GB or more.

git clone --depth 1 --branch self-hosted/v0.8.1 https://github.com/supabase/supabase
mkdir supabase-project
cp -rf supabase/docker/. supabase-project
cd supabase-project && cp .env.example .env
printf 'ref=self-hosted/v0.8.1\n' > .supabase-version

Stop here and edit .env. The guide's warning is direct: never start with the example values. Set POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY and DASHBOARD_PASSWORD to your own values, because the API keys are signed with the JWT secret, and a known secret means anyone can mint a service-role token for your database. Then:

docker compose pull
sh run.sh start
docker compose ps

run.sh start is the guide's wrapper for docker compose up -d --wait, and after a minute or less every service should show Up (healthy). The dashboard answers on port 8000 through the gateway, behind HTTP basic authentication using the dashboard password you set. The full Supabase self-hosting walkthrough covers the reverse proxy and the SMTP setup. Before you go this route, the honest maths on Supabase's cloud free tier against a VPS is worth ten minutes, because for a small app the hosted free tier is often the cheaper answer in hours.

Appwrite: Docker Compose with many workers

Appwrite is the largest stack here. Its self-hosting guide, checked 2026-09-19, asks for 2 CPU cores and 4 GB of RAM, plus 2 GB of swap and Docker Compose version 2. The install is one docker run that starts a setup wizard on port 20080:

mkdir -p ~/apps && cd ~/apps
docker run -it --rm \
    --publish 20080:20080 \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
    --entrypoint="install" \
    appwrite/appwrite:2.2.0

Open port 20080 in your firewall for the duration of the setup, then close it; the wizard is the only thing that uses it. The wizard's four steps cover the app settings, the security keys (_APP_OPENSSL_KEY_V1 and _APP_EXECUTOR_SECRET, which must be unique per install), your first account, and a review. It writes docker-compose.yml and .env into ./appwrite. From that directory:

cd appwrite
docker compose up -d --remove-orphans
docker compose ps

If the wizard already started the stack, the up command changes nothing. Then open the console at your server's hostname; Traefik inside the stack handles ports 80 and 443. The Docker socket mount in the install command matters. Appwrite starts function runtimes and builds as sibling containers through that socket, and a process that can talk to the Docker daemon is a process with root on the host. Run it on a VPS that does only this.

What you get for that weight is the most complete Firebase feature map of the four: databases, auth with many OAuth providers and MFA, storage buckets, functions in many language runtimes, realtime over WebSocket, a messaging service that sends email and push through providers, and Sites for hosting frontends. The compose file also names a ClickHouse container for usage stats and three database engines, of which the wizard picks one. Upgrades follow the project's migration tool and its release notes, and the more containers a stack has, the more often one of them needs attention after a pull. Docker Compose basics for a VPS is the prerequisite reading if docker compose ps output is new to you.

Nhost and Kuzzle, briefly

Nhost is Postgres, Hasura GraphQL, an auth service and storage, with a serverless functions runtime. Its docker-compose example in the repository starts ten containers, including Mailhog and Traefik that you would remove for production, and carries two lines you should read first: "We don't officially support self-hosting without a support agreement" and "This example is for demonstration purposes only". Take that at face value. It works, and you are on your own. Kuzzle is a Node.js backend that depends on Elasticsearch and Redis, and its getting-started guide scaffolds a compose stack for you; it is aimed at IoT and geolocation workloads more than at a Firestore migration. Neither one is a bad project. Neither one is the first thing to try on a 4 GB VPS.

Mapping Firebase features to their self-hosted equivalents

Each line names the Firebase product first and then what replaces it in each backend.

  • Cloud Firestore and Realtime Database. PocketBase stores collections in SQLite. Supabase, and Parse Server with the Postgres adapter, give you Postgres. Parse Server's default is MongoDB, which is the closest match to Firestore's document model. Appwrite stores documents in its own database service, backed by Postgres by default, with MariaDB and MongoDB as the other options. In every case you write queries against a real database instead of Firestore's query language, which is a change in your app code as well as in your hosting.
  • Security rules. Firestore rules become row level security policies in Supabase, per-collection API rules in PocketBase, per-document permissions in Appwrite, and class-level permissions plus ACLs in Parse Server. All four are enforced on the server, so the same "clients are untrusted" model applies.
  • Authentication. All four ship email and password sign-in with OAuth2 providers. MFA is built in everywhere except Parse Server, which has an auth adapter system you configure per provider.
  • Cloud Storage. PocketBase writes to local disk or S3-compatible storage. Supabase Storage and Appwrite Storage use buckets with per-object rules. Parse Server stores files in the database by default and moves to S3 through an adapter.
  • Cloud Functions. Supabase Edge Functions run on a Deno runtime in their own container. Appwrite Functions run in per-language runtime containers. Parse Server's Cloud Code runs in the Parse process itself. PocketBase has JavaScript hooks in pb_hooks/ and can be extended in Go, but has no separate function runtime.
  • Realtime updates. PocketBase uses server-sent events on record changes. Supabase Realtime and Appwrite Realtime use WebSockets. Parse Server has LiveQuery, also over WebSockets.
  • Hosting. None of these is a CDN. Appwrite Sites hosts frontends inside the stack; for the others, serving a website from the same VPS with nginx or Caddy is the equivalent of Firebase Hosting.

Which Firebase features have no drop-in

Offline sync, first and most important. Firestore's client SDKs keep a local cache and accept writes while the device is offline, then replay them when the network returns, with conflict handling you never had to write. None of these four backends ships that. The client SDKs for PocketBase, Supabase, Appwrite and Parse all talk to the live server and stop when the network stops. Parse Server's iOS and Android SDKs add a Local Datastore that pins objects on the device, but pushing queued writes back and resolving conflicts is your code. If your app is a field tool that must work in a basement, this is the section that decides your migration, and the honest answer may be to stay.

Push notifications. Cloud Messaging is Google's delivery network. Appwrite Messaging and Parse Server's push adapters both send through FCM and APNs, so you keep a Google project for delivery even after the backend moves. Nothing self-hosted replaces the transport.

Analytics, Crashlytics, Remote Config and A/B testing. None of the four covers them. They are separate products with separate self-hosted answers, and they are outside this comparison.

A hosted, edge-cached CDN. App Hosting and Firebase Hosting put your frontend on Google's edge. A VPS is one location. That is fine for most apps, and a real difference for a global audience.

Who should stay on Firebase

Stay if your app depends on Firestore offline persistence. Stay if the free tier covers your traffic and nobody on the team wants to own a server; a migration that saves 20 dollars a month and costs a weekend every quarter is a loss. Stay if you lean on Cloud Messaging and Crashlytics together, because you would be replacing one vendor with several. And if the only thing you used was Firebase Studio, move your editor and leave the backend alone. The migration page says the backend is not going anywhere.

Move if per-read billing is unpredictable, if the data must stay in one country, if you need SQL, or if you want a backend you can copy to another host in an afternoon. Those are the honest reasons, and each of the four backends above serves them.

Putting a migrated app on the VPS

A backend alone is not the app. The frontend that was on Firebase Hosting needs a home on the same box, and the pattern in hosting an AI-generated app on a VPS applies to any single-page app that now points at PocketBase or Supabase instead of Firebase: build it and serve the static files from nginx, with the API path proxied to the backend on localhost. Keep the backend bound to 127.0.0.1 and let the proxy own TLS.

FAQ

Is Firebase shutting down?

No. Firebase Studio, the browser IDE, is shutting down on 2027-03-22 after stopping new workspaces on 2026-06-22. Google's migration page states that Cloud Firestore, Authentication, App Hosting and the other backend services are not affected and that databases and user data continue to work normally. Only the editor is going away.

What is the cheapest self-hosted Firebase alternative to run?

PocketBase. It is one Go binary with SQLite inside, so it is one process under one systemd unit, with no Docker and no separate database. The project publishes no minimum RAM; its FAQ describes a 2 vCPU, 4 GB VPS serving more than 10,000 realtime connections. Its limits are that it scales on one server only, and that backward compatibility is not guaranteed before v1.0.0.

Does self-hosted Supabase or PocketBase support offline sync like Firestore?

No. Firestore's client SDKs cache data and queue writes while offline, then replay them later. The client SDKs for PocketBase, Supabase, Appwrite and Parse all talk to the live server. Parse's mobile SDKs can pin objects locally but do not sync queued writes for you. If offline-first matters, that is a reason to stay on Firestore or to add a separate sync layer.

How many containers does self-hosted Supabase run?

11, at the ref self-hosted/v0.8.1 that the Docker guide pins as of 2026-09-19: the dashboard, an Envoy gateway, auth, REST, realtime, storage, an image proxy, postgres-meta, edge functions, Postgres itself and the Supavisor pooler. Run docker compose ps -q | wc -l in your project directory to count yours. The guide's minimum is 4 GB RAM, and it recommends 8 GB or more.

Can I self-host Firebase itself?

No. Firebase's services run only on Google's infrastructure. The Firebase Local Emulator Suite runs Firestore, Auth, Functions and Storage on your machine for development, but it is not built for production and keeps data in memory unless you export it. The four backends above are the practical answer.

#firebase#supabase#pocketbase#appwrite#baas#self-hosting