PocketBase vs Appwrite: Which Backend to Self-Host?

Quick Verdict

PocketBase is the better choice for most self-hosters. It runs as a single Go binary with an embedded SQLite database, uses under 30 MB of RAM, and gives you auth, real-time subscriptions, file storage, and a REST API out of the box — no Docker required, though you can containerize it trivially. Appwrite is the pick when you need a full-featured BaaS with server-side functions, team management, messaging, and multi-database support — but it demands 2+ GB RAM and a multi-container Docker stack with MariaDB, Redis, and a reverse proxy.

If you are building a side project, internal tool, or MVP: PocketBase. If you are building a production SaaS that needs cloud functions, granular permissions, and multiple SDKs with enterprise features: Appwrite.

Overview

PocketBase is an open-source backend written in Go that ships as a single executable. It bundles SQLite for data storage, built-in auth (email/password, OAuth2), file storage, real-time subscriptions via SSE, and an admin dashboard UI — all in one binary under 40 MB. It can also be used as a Go framework for extending with custom routes and middleware. Created by Gani Georgiev, it has grown rapidly since its 2022 release. PocketBase is still pre-1.0 (currently v0.36.5), so breaking changes are possible between minor versions.

Appwrite is an open-source backend-as-a-service (BaaS) platform designed as a self-hosted Firebase alternative. It provides auth, databases, storage, serverless functions, messaging, real-time, and a web console. Under the hood, Appwrite runs as a multi-container Docker application with MariaDB for data, Redis for caching, and Traefik for routing. It is backed by a well-funded company (Appwrite Ltd.) and has a large contributor ecosystem. The current stable release is 1.8.1.

Feature Comparison

FeaturePocketBaseAppwrite
Authentication (email/password)YesYes
OAuth2 providersYes (30+ providers)Yes (40+ providers)
DatabaseEmbedded SQLiteMariaDB (managed internally)
Real-time subscriptionsYes (SSE)Yes (WebSocket)
File storageYes (local filesystem)Yes (local, S3, and other providers)
Server-side functionsNo (extend via Go framework)Yes (Node.js, Python, PHP, Dart, Ruby, and more)
REST APIYesYes
GraphQL APINoYes
SDKsJavaScript, DartJavaScript, Flutter, Apple, Android, Python, Ruby, .NET, and more
Admin dashboardYes (embedded web UI)Yes (full web console)
Team/organization managementBasic (collections-based)Yes (teams, roles, granular permissions)
WebhooksNo (use real-time or extend in Go)Yes
Messaging (email, SMS, push)NoYes
Database migrationsYes (auto-generated)Yes
Backup & restoreSQLite file copyMulti-service backup required
Self-hosting complexitySingle binary, zero dependenciesMulti-container Docker stack
Minimum RAM~20-30 MB~2 GB
LicenseMITBSD-3-Clause
Managed cloud offeringNo (self-host only)Yes (Appwrite Cloud)

Architecture Differences

This is the fundamental divide between these two platforms and the reason they appeal to different audiences.

PocketBase compiles to a single Go binary. Everything — the HTTP server, SQLite database engine, auth layer, file storage handler, admin UI, and real-time subscription server — lives inside one process. Your entire backend is one file on disk and one process in memory. Data lives in a SQLite database file. File uploads live in a directory on the filesystem. There is no connection pooling, no cache layer, no message queue, no service mesh. This is by design — PocketBase trades horizontal scalability for operational simplicity.

The tradeoff: SQLite handles concurrent writes via WAL mode, but it is still a single-writer database. For read-heavy workloads with moderate writes, PocketBase performs well. For write-heavy workloads with hundreds of concurrent writers, SQLite becomes the bottleneck. PocketBase is not designed for horizontal scaling — you cannot run multiple PocketBase instances against the same database file.

Appwrite runs as a fleet of Docker containers orchestrated by Docker Compose. The main appwrite container handles the REST/GraphQL API. Separate containers handle real-time connections, background workers (for functions, emails, webhooks, and database operations), and the admin console. MariaDB stores relational data. Redis handles caching, pub/sub, and queue management. Traefik acts as the ingress reverse proxy. A typical Appwrite installation runs 10+ containers.

The tradeoff: this architecture supports horizontal scaling, large teams, and heavy workloads — but it requires significantly more resources, more operational knowledge, and more monitoring. A failed Redis container takes down your real-time features. A MariaDB issue takes down everything.

Installation Complexity

PocketBase Docker Setup

PocketBase does not provide an official Docker image. You can run it directly as a binary (./pocketbase serve) or containerize it yourself. Here is a minimal Docker Compose setup using an Alpine base image:

services:
  pocketbase:
    image: alpine:3.21
    container_name: pocketbase
    restart: unless-stopped
    command: >
      sh -c "
        wget -qO /tmp/pb.zip https://github.com/pocketbase/pocketbase/releases/download/v0.36.5/pocketbase_0.36.5_linux_amd64.zip &&
        unzip -o /tmp/pb.zip -d /pb/bin &&
        chmod +x /pb/bin/pocketbase &&
        /pb/bin/pocketbase serve --http=0.0.0.0:8090 --dir=/pb/data
      "
    ports:
      - "8090:8090"
    volumes:
      - pocketbase_data:/pb/data
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://localhost:8090/api/health"]
      interval: 30s
      timeout: 5s
      retries: 3

volumes:
  pocketbase_data:

That is the entire stack. One container, one volume, one port. Start it:

docker compose up -d

Access the admin dashboard at http://your-server:8090/_/ and create your first superuser account.

For a production setup, you would typically download the binary directly onto the host and manage it with systemd instead of Docker — it eliminates a layer of abstraction for a tool that is already self-contained. But the Docker setup above works and keeps everything consistent if you manage all services via Compose.

Appwrite Docker Setup

Appwrite provides an automated installer that generates the Docker Compose configuration:

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:1.8.1

The installer prompts for your HTTP/HTTPS ports, encryption secret key, and hostname, then generates a docker-compose.yml and .env file. The resulting stack includes:

  • appwrite — the main API server
  • appwrite-realtime — WebSocket server for real-time subscriptions
  • appwrite-worker-* — multiple background workers (audits, webhooks, deletions, databases, builds, functions, emails, messaging)
  • appwrite-console — the admin web console
  • mariadb — relational database
  • redis — caching and message queue
  • traefik — reverse proxy and SSL termination

You can also set it up manually. Here is a minimal production .env for Appwrite:

# Core
_APP_ENV=production
_APP_OPENSSL_KEY_V1=your-secret-encryption-key-min-128-bits
_APP_DOMAIN=appwrite.yourdomain.com
_APP_CONSOLE_DOMAIN=appwrite.yourdomain.com

# Database
_APP_DB_HOST=mariadb
_APP_DB_PORT=3306
_APP_DB_SCHEMA=appwrite
_APP_DB_USER=appwrite
_APP_DB_PASS=change-this-strong-password
_APP_DB_ROOT_PASS=change-this-root-password

# Redis
_APP_REDIS_HOST=redis
_APP_REDIS_PORT=6379

# Storage
_APP_STORAGE_DEVICE=Local
_APP_STORAGE_LIMIT=30000000

# Functions
_APP_FUNCTIONS_TIMEOUT=900

Start the stack:

docker compose up -d

Appwrite’s system requirements: 2 CPU cores, 4 GB RAM, 2 GB swap. That is the minimum — production deployments with functions and active users will need more.

Performance and Resource Usage

MetricPocketBaseAppwrite
Idle RAM~20-30 MB~1.5-2 GB
Under load RAM~50-150 MB~3-4 GB
Minimum disk~50 MB (binary + empty DB)~2 GB (images + databases)
Cold start time<1 second30-60 seconds (multi-container startup)
Container count1 (or 0 if running bare)10+
CPU at idleNegligibleLow-moderate (worker polling)

PocketBase is extraordinarily lightweight. It can run comfortably on a Raspberry Pi 4 alongside other services. The entire application fits in the CPU cache on a modern server.

Appwrite’s resource footprint is typical for a full BaaS platform. MariaDB and Redis alone account for most of the idle memory. The multiple worker containers add overhead even when idle because they poll for tasks. Running Appwrite alongside other services on a 4 GB VPS is tight — 8 GB is more realistic for production.

Developer Experience

PocketBase prioritizes simplicity. The API follows predictable REST conventions. Collections (tables) are created in the admin UI or via migration files. You define fields, set validation rules, and PocketBase generates CRUD endpoints automatically. The JavaScript and Dart SDKs cover all API operations. For anything the built-in features do not cover, you can use PocketBase as a Go framework — import it, add custom routes, middleware, and hooks, then compile your own extended binary.

The limitation: no server-side functions in the traditional sense. If you need to run background jobs, scheduled tasks, or complex server logic, you either extend PocketBase in Go or run a separate service alongside it.

Appwrite provides a richer developer experience with more SDKs (JavaScript, Flutter, Apple, Android, Python, Ruby, .NET), a GraphQL API alongside REST, and built-in serverless functions that execute in isolated containers. The web console is polished and full-featured. Team management, role-based access, and granular permissions are first-class features. Appwrite also handles messaging (email, SMS, push notifications) natively.

The limitation: the learning curve is steeper. The number of concepts — projects, databases, collections, documents, buckets, functions, teams, memberships, roles — is significantly larger. Configuration involves more environment variables and more moving parts.

Use Cases

Choose PocketBase If…

  • You are building a side project, internal tool, or prototype
  • You want the simplest possible backend that just works
  • Your server has limited resources (1-2 GB RAM)
  • You are comfortable with Go and want to extend the backend with custom logic
  • You need a mobile app backend with auth and real-time sync
  • You are a solo developer or small team
  • You value operational simplicity over feature breadth
  • Your write workload is moderate (not thousands of concurrent writes per second)

Choose Appwrite If…

  • You are building a production application with a team of developers
  • You need serverless functions for background processing
  • You need granular team permissions and role-based access control
  • You need multiple database support or plan to scale horizontally
  • You want native messaging (email, SMS, push notifications) from your backend
  • You need a GraphQL API
  • You prefer SDKs in Python, Ruby, .NET, or other languages beyond JS/Dart
  • You plan to eventually use a managed cloud offering

Final Verdict

PocketBase wins for the majority of self-hosters. The ratio of capability to complexity is unmatched — you get auth, database, file storage, real-time, and an admin UI in a single process that uses 30 MB of RAM. For personal projects, small SaaS apps, mobile backends, and internal tools, it is the obvious choice. The pre-1.0 status means you should expect occasional breaking changes on upgrades, but the project is actively maintained and the migration path between versions is well-documented.

Appwrite is the right choice when your requirements explicitly demand what PocketBase lacks: serverless functions, team/organization management with granular RBAC, messaging, GraphQL, or the confidence of a funded company with a managed cloud option. These are real production needs — but most self-hosters building personal or small-scale projects do not need them and should not pay the 10x resource overhead to get them.

Start with PocketBase. If you outgrow it, Appwrite will be there.