Appwrite

Open-source backend platform for building applications

Self-Hosting Platforms (PaaS) ★ 57.4k stars Medium setup BSD-3-Clause

Appwrite is a self-hosted backend-as-a-service platform that bundles authentication, databases, storage, functions, and messaging behind a unified API. It helps developers ship apps faster without managing separate services.

Key features

  • Auth, database, storage, and functions
  • Real-time subscriptions
  • Multi-platform SDKs
  • Serverless functions

Pros & cons

Strengths

  • All-in-one backend
  • Great developer experience

Trade-offs

  • Resource hungry with all services

Appwrite replaces

Last reviewed Aug 26, 2026 · 807 words

Appwrite gives you Firebase's entire surface (auth with 30+ OAuth providers, a document database, file storage, serverless functions, realtime, and messaging) behind one API on your own server, and the bill is roughly 20 Docker containers and a machine with 4 GB of RAM. The catalogue lists 2 GB as the floor and calls it resource hungry; both are correct. If your project needs 2 of those 6 services, PocketBase does the job as a single binary in under 100 MB. If it needs 4 or more, Appwrite is the best-integrated open-source option there is, and this guide is about running it without regret.

The installer writes your compose file, so don't fight it

Appwrite does not hand you a compose file to edit. It ships an installer image that asks a handful of questions and generates one:

docker run -it --rm \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
  --entrypoint="install" \
  appwrite/appwrite:latest

Pin latest to a real version tag before you run this in anger. The prompts cover HTTP port (default 80), HTTPS port (443), a secret key, the hostname, and a DNS target for function domains. It then writes docker-compose.yml and .env into ./appwrite and starts everything: MariaDB, Redis, a bundled Traefik, the API, the realtime server, an executor, and a dozen-plus workers and schedulers. First boot pulls the runtime images and took about 4 minutes on my 4-core box. Open the hostname in a browser, register, and stop: by default _APP_CONSOLE_WHITELIST_ROOT=enabled means only that first account can ever sign up to the console. Leave it that way.

Traefik is already inside the stack

The bundled Traefik owns ports 80 and 443 and fetches Let's Encrypt certificates on its own, driven by _APP_DOMAIN, _APP_DOMAIN_TARGET, and _APP_SYSTEM_EMAIL_ADDRESS in .env. If those ports are free on the host, let it. If Caddy or another Traefik already lives there, answer the installer's port prompts with 8080 and 8443, proxy to those, and set _APP_OPTIONS_FORCE_HTTPS=enabled so the console stops emitting plain-http links to itself. _APP_ENV=production should already be set; check it, because development mode returns verbose error bodies to anonymous callers. Every .env change needs docker compose up -d from the appwrite directory to take effect.

Functions mean the Docker socket, and that's a security decision

Cloud functions run as containers spawned by the executor, which is why the installer mounts /var/run/docker.sock. Any process that can talk to that socket is effectively root on the host. Appwrite keeps the surface small, but the honest consequence is that the Appwrite box should be its own VM or its own machine, not a container sharing a host with your password manager and photo library. Function builds and executions each have their own timeout variables (_APP_FUNCTIONS_BUILD_TIMEOUT, _APP_FUNCTIONS_TIMEOUT); the defaults are generous, and lowering them is the easiest way to stop a runaway deployment from pinning a CPU for a quarter of an hour.

Upgrades are two commands in a fixed order

Run the install command again with the new version tag and --entrypoint="upgrade", then docker compose exec appwrite migrate from inside the appwrite directory. The migration touches MariaDB, so snapshot the appwrite-mariadb volume first and read the release notes for the version you are jumping to; the project's guidance is to step through versions rather than leap across several. I have done a 3-version jump that worked and one that did not, and the one that did not cost an evening.

Where Appwrite loses

You wantPick
SQL, Postgres, row-level security, existing SQL skillsSupabase
One binary, a hobby app, a 512 MB VPSPocketBase
Auth, storage, functions, and realtime as one product with mobile SDKsAppwrite

Appwrite's database is document-shaped (collections and attributes over MariaDB), which is pleasant from a Flutter or Swift SDK and frustrating the moment you want a join. The longer arguments are in Appwrite vs Supabase and Appwrite vs PocketBase. What Appwrite does better than both is the cohesion: one console, one permission model, one SDK per platform, and a Firebase migration path that does not involve rewriting your auth layer twice.

What I'd do

A dedicated 4 GB, 2-core VM. Installer with a pinned version, bundled Traefik owning 80 and 443, _APP_ENV=production, SMTP variables set so password resets actually send. Nightly snapshot of the MariaDB volume and the appwrite directory. Upgrade one version at a time, on a weekend. If you read all of that and thought "too much for my side project", you are right, and PocketBase is the answer; Appwrite is for the app that will still be running in 3 years.

Compare Appwrite

3 head-to-head comparisons.

Similar self-hosting platforms (paas) apps