Appwrite is an open-source, self-hostable backend-as-a-service platform bundling Auth, Databases, Storage, Functions, Messaging, Realtime and static-site hosting behind REST, GraphQL and realtime APIs, with client SDKs for web, mobile and server platforms.
- Language
- PHP
- Database
- PostgreSQL
- Hosting
- Docker
- License
- BSD-3-Clause
- Running for
- 5 years 8 months
- Team
- 20+ people
Why this architecture
A single PHP/Swoole codebase shares its API and worker processes so every product (Auth, Databases, Functions, Realtime) scales as copies of one image, while pluggable adapters keep PostgreSQL and Redis as defaults without hard-coding them.
Tech stack by layer
8 technologies · audited Sep 17, 2026- PHPRuns the API server, CLI, and every worker process; requires PHP >=8.5 in composer.json.
- SwooleCoroutine-based async runtime the HTTP and worker entrypoints run on (ext-swoole 6.* required).
- Utopia PHP framework familyAppwrite's own micro-framework packages (utopia-php/http, cli, database, queue, storage, platform, etc.) form the app skeleton.
- GraphQLwebonyx/graphql-php exposes an optional GraphQL API alongside the REST endpoints.
- PostgreSQLDefault database adapter; the appwrite service's depends_on falls back to a `postgresql` host.
- RedisBacks caching, pub/sub for realtime, and the queue that worker-* binaries consume.
- GitHub ActionsCI, CodeQL, nightly builds, SDK-preview generation, and release/publish workflows.
- PHPUnit, PHPStan, PintTest, static-analysis, and formatting scripts declared in composer.json (test, analyze, lint, format).
Appwrite architecture diagram
Open SVGDiagram as text
- Client SDKs (web · mobile · server) → Reverse proxy (Traefik): REST · GraphQL
- Console (web UI) → Reverse proxy (Traefik): HTTPS
- Reverse proxy (Traefik) → API server (PHP · Swoole · Utopia): route
- Reverse proxy (Traefik) → Realtime (realtime.php): websocket
- API server (PHP · Swoole · Utopia) → PostgreSQL (default DB adapter): utopia database
- API server (PHP · Swoole · Utopia) → Redis (cache · pub/sub · queue): enqueue
- Redis (cache · pub/sub · queue) → Workers (worker-* binaries): jobs
- Realtime (realtime.php) → Redis (cache · pub/sub · queue): pub/sub
- Workers (worker-* binaries) → Functions & Sites (isolated runtimes): run
Key architectural decisions
5 decisions- 01
The whole platform is one PHP monolith on Swoole, not microservices
app/http.php serves the API and app/worker.php drives background jobs from the same codebase, both running on the Swoole coroutine server declared as ext-swoole 6.* in composer.json. Horizontal scaling comes from running many copies of the same image (see bin/worker-* entrypoints) rather than splitting into separate services.
- 02
A family of small utopia-php packages replaces a general web framework
composer.json requires dozens of first-party utopia-php/* packages (http, cli, database, queue, storage, platform, validators, domains, dsn) instead of Laravel or Symfony. Three of them (packages/agents, packages/bus, packages/lock) even live inside this repo as PSR-4 autoloaded workspace packages with their own composer.json and test suites.
- 03
Database and cache are pluggable but default to PostgreSQL and Redis
docker-compose.yml wires the appwrite service to depend on
${_APP_DB_HOST:-postgresql}andredis, and the environment variable list includes a full_APP_DB_ADAPTERfamily plus separate_APP_DB_*_VECTORSDBand_APP_DB_*_DOCUMENTSDBsettings, so the same server can point at different adapters per workload. - 04
Sites and Functions run as isolated runtimes, not in the API process
bin/worker-builds and bin/worker-functions, together with the open-runtimes/sdk-for-php dependency, show that user-submitted Functions and Sites deployments are built and executed by dedicated worker/executor processes (src/Executor), keeping arbitrary user code out of the main API process.
- 05
Client and server SDKs are generated, not hand-written per platform
The README lists first-party SDKs for Web, Flutter, Apple, Android, React Native, Node.js, Python, Dart, PHP, Ruby, .NET and more, each in its own appwrite/sdk-for-* repository generated from the shared appwrite/sdk-generator project rather than maintained by hand in this repo.
How Appwrite is built
How Appwrite is structured
The repository is a PHP monorepo rooted in a single composer.json (namespace appwrite/server-ce) with a small npm workspace layered on top for tooling like Prettier on the Docker Compose files. Application code lives under app/ (http.php for the API, worker.php for background jobs, cli.php, realtime.php, init.php, plus app/config, app/controllers, app/views), and src/Appwrite and src/Executor hold the PSR-4 autoloaded core classes. bin/ contains dozens of thin entrypoint scripts (worker-databases, worker-functions, schedule-executions, queue-retry, and more) that all boot the same application but run a different worker loop.
Three internal packages are vendored as their own composer projects inside packages/: packages/agents (a PHP AI-agents library), packages/bus (a synchronous in-process event bus), and packages/lock (cross-coroutine/process locking). Each has its own composer.json, PSR-4 autoloading, and test suite, and the root composer.json replaces them with utopia-php/agents, utopia-php/bus, and utopia-php/lock so they can also be split out as standalone packages later.
Backend & APIs
The API is not built on a general-purpose framework. Instead, composer.json requires a large family of first-party utopia-php/* packages — http (2.0 RC) for the HTTP layer, cli for command dispatch, database for the storage abstraction, queue for jobs, storage for file adapters, platform for module wiring, plus validators, domains, dsn, auth, openapi, and others. webonyx/graphql-php adds an optional GraphQL API alongside the REST surface described by app/config route definitions and the generated OpenAPI specs under docs/references.
All of this runs on Swoole: composer.json requires ext-swoole: 6.*, and both app/http.php and app/worker.php are Swoole coroutine servers rather than traditional PHP-FPM scripts. Products like Functions and Sites do not execute user code inline — bin/worker-builds, bin/worker-functions, and src/Executor hand that off to isolated runtimes via the open-runtimes/sdk-for-php dependency, so a bad user function cannot take down the API process.
Data & persistence
The database layer is adapter-based through utopia-php/database, but docker-compose.yml shows the concrete default: the appwrite service's depends_on list falls back to ${_APP_DB_HOST:-postgresql}, i.e. PostgreSQL unless overridden. The compose environment also defines separate connection variables for a vector database (_APP_DB_*_VECTORSDB) and a documents database (_APP_DB_*_DOCUMENTSDB), indicating the same adapter pattern is reused for specialised stores that back newer AI-related features. Redis is wired in alongside Postgres (_APP_REDIS_HOST/_APP_REDIS_PORT env vars, and redis in depends_on) and backs caching, queueing, and realtime pub/sub. File storage is likewise adapter-based, with environment variables for S3, DigitalOcean Spaces, Backblaze, Linode, and Wasabi alongside a local device option.
Realtime / collaboration
app/realtime.php and the bin/realtime entrypoint implement Appwrite's realtime channel, which subscribes clients to database, storage, and account events over WebSocket connections and fans them out through Redis pub/sub so any API node can publish an event any connected node can deliver.
Build, test & deploy
composer.json defines test (PHPUnit), lint/format (Laravel Pint), analyze/check (PHPStan with a dedicated phpstan-deadcode.neon), bench (PHPBench), and refactor/refactor:check (Rector) scripts. .github/workflows runs ci.yml for the main test matrix, codeql-analysis.yml and security-scan.yml for security scanning, nightly.yml for scheduled builds, specs.yml to regenerate API specs, and sdk-preview.yml/split.yml/split-dev.yml to publish the generated client/server SDKs and monorepo splits. release.yml and publish.yml handle image and package releases.
Self-hosting notes
The Dockerfile is a multi-stage build: a composer stage installs PHP dependencies (skipping dev packages unless TESTING=true), a base stage on appwrite/base:2.1.0 copies in application code and creates the /storage/* volume directories, and separate production, development, and xdebug targets branch from there — the development target mounts the xdebug build's extension via a RUN --mount=from=xdebug layer instead of duplicating the base image. docker-compose.yml runs Traefik in front of the appwrite container, routing all paths to it and terminating TLS, while docker-compose.override.yml and docker-compose.separate.yml provide development and split-service variants. The published quick-start is docker run --entrypoint=install appwrite/appwrite:<version> against the host's Docker socket, which then generates the compose files for a full local stack.
What to copy (and what not to)
The worker-per-concern pattern (one bin/worker-* script per job type, all sharing the same application bootstrap) is a clean way to add background processing without introducing a second framework or language. The internal utopia-php/* package family is harder to justify outside Appwrite: it trades a well-known framework's ecosystem and documentation for full control over every layer, which only pays off at this scale and with a team maintaining the packages long-term. The adapter-based database and storage layers are worth copying if you genuinely need to support multiple backends (Postgres, MariaDB, S3-compatible storage, and so on) for self-hosters, but add real complexity if you only ever run one.
Sources & repo audit
- Audited
- Sep 17, 2026
- Commit
- 7ae78b5
- License
- BSD-3-Clause
- composer.json (PHP >=8.5, Swoole, utopia-php/* packages, PHPUnit/PHPStan/Pint scripts)
- Dockerfile (Composer build stage, production/development/xdebug targets)
- docker-compose.yml (traefik + appwrite services, DB/Redis env vars)
- packages/agents, packages/bus, packages/lock (in-repo utopia-php workspace packages)
- .github/workflows (ci, codeql-analysis, nightly, sdk-preview, release, split)
Independent analysis of repository at github.com/appwrite/appwrite. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/appwrite)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Appwrite's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Appwrite" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Appwrite**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Appwrite
- **What It Does**: Appwrite is an open-source, self-hostable backend-as-a-service platform bundling Auth, Databases, Storage, Functions, Messaging, Realtime and static-site hosting behind REST, GraphQL and realtime APIs, with client SDKs for web, mobile and server platforms.
- **Domain & Category**: Backend-as-a-Service
- **Production Scale**: 20+ people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: A single PHP/Swoole codebase shares its API and worker processes so every product (Auth, Databases, Functions, Realtime) scales as copies of one image, while pluggable adapters keep PostgreSQL and Redis as defaults without hard-coding them.
- **Live Website Reference**: https://appwrite.io
- **Source Repository**: https://github.com/appwrite/appwrite
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: PHP, Swoole, TypeScript, PostgreSQL, Redis, Docker, Traefik, GraphQL
- **Primary Language(s)**: PHP, TypeScript
- **License of the reference repo**: BSD-3-Clause
- **Backend & APIs**: PHP — Runs the API server, CLI, and every worker process; requires PHP >=8.5 in composer.json.; Swoole — Coroutine-based async runtime the HTTP and worker entrypoints run on (ext-swoole 6.* required).; Utopia PHP framework family — Appwrite's own micro-framework packages (utopia-php/http, cli, database, queue, storage, platform, etc.) form the app skeleton.; GraphQL — webonyx/graphql-php exposes an optional GraphQL API alongside the REST endpoints.
- **Data & persistence**: PostgreSQL — Default database adapter; the appwrite service's depends_on falls back to a `postgresql` host.; Redis — Backs caching, pub/sub for realtime, and the queue that worker-* binaries consume.
- **Infrastructure & deploy**: Docker — Multi-stage Dockerfile builds Composer dependencies, then production/development/xdebug image variants.; Traefik — Reverse proxy in docker-compose.yml that routes HTTP/HTTPS to the appwrite container via Docker labels.
- **Tooling, testing & ops**: GitHub Actions — CI, CodeQL, nightly builds, SDK-preview generation, and release/publish workflows.; PHPUnit, PHPStan, Pint — Test, static-analysis, and formatting scripts declared in composer.json (test, analyze, lint, format).
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/appwrite/appwrite @ 7ae78b5)
1. **The whole platform is one PHP monolith on Swoole, not microservices**: app/http.php serves the API and app/worker.php drives background jobs from the same codebase, both running on the Swoole coroutine server declared as ext-swoole 6.* in composer.json. Horizontal scaling comes from running many copies of the same image (see bin/worker-* entrypoints) rather than splitting into separate services.
2. **A family of small utopia-php packages replaces a general web framework**: composer.json requires dozens of first-party utopia-php/* packages (http, cli, database, queue, storage, platform, validators, domains, dsn) instead of Laravel or Symfony. Three of them (packages/agents, packages/bus, packages/lock) even live inside this repo as PSR-4 autoloaded workspace packages with their own composer.json and test suites.
3. **Database and cache are pluggable but default to PostgreSQL and Redis**: docker-compose.yml wires the appwrite service to depend on `${_APP_DB_HOST:-postgresql}` and `redis`, and the environment variable list includes a full `_APP_DB_ADAPTER` family plus separate `_APP_DB_*_VECTORSDB` and `_APP_DB_*_DOCUMENTSDB` settings, so the same server can point at different adapters per workload.
4. **Sites and Functions run as isolated runtimes, not in the API process**: bin/worker-builds and bin/worker-functions, together with the open-runtimes/sdk-for-php dependency, show that user-submitted Functions and Sites deployments are built and executed by dedicated worker/executor processes (src/Executor), keeping arbitrary user code out of the main API process.
5. **Client and server SDKs are generated, not hand-written per platform**: The README lists first-party SDKs for Web, Flutter, Apple, Android, React Native, Node.js, Python, Dart, PHP, Ruby, .NET and more, each in its own appwrite/sdk-for-* repository generated from the shared appwrite/sdk-generator project rather than maintained by hand in this repo.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (PostgreSQL, Redis): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Appwrite
What is Appwrite built with?
Appwrite's server is PHP 8.5+ running on the Swoole coroutine runtime, built from dozens of first-party utopia-php/* packages rather than a general framework like Laravel. It uses PostgreSQL by default for its database and Redis for caching, pub/sub, and queues, all packaged behind a Traefik reverse proxy.
Does Appwrite need a backend?
Appwrite is the backend: it is a self-hosted or cloud backend-as-a-service that provides Auth, Databases, Storage, Functions, Messaging, and Realtime through REST and GraphQL APIs, consumed by thin client and server SDKs rather than a custom backend you write yourself.
Can I self-host Appwrite?
Yes. The repository ships a Dockerfile and docker-compose.yml (plus docker-compose.override.yml and docker-compose.separate.yml) for running the full stack with docker run --entrypoint=install appwrite/appwrite:<version>, and the README documents one-click installs on DigitalOcean, Akamai/Linode, and AWS Marketplace.
How does Appwrite handle realtime and background jobs?
app/realtime.php and bin/realtime implement the realtime layer, and Redis backs both realtime pub/sub and the job queue that dedicated bin/worker-* processes (builds, databases, functions, messaging, webhooks, and more) consume, keeping long-running or user-submitted work off the main API process.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- HoppscotchClassicAPI Testing Client · 6-20 peopleShares TypeScript · GraphQL · PostgreSQL
- PenpotClassicDesign & Prototyping Platform · 20+ peopleShares TypeScript · PostgreSQL · Redis
- Trigger.devHybridJob Queue / Dev Tool · 6-20 peopleShares TypeScript · PostgreSQL · Redis
- TwentyHybridCRM SaaS · 6-20 peopleShares TypeScript · PostgreSQL · Redis
- CoolifyAI-agentSelf-Hosted Cloud PaaS · SoloShares PHP · PostgreSQL · Redis
- GiteaClassicLightweight Self-Hosted Git Service · 20+ peopleShares TypeScript · PostgreSQL · Redis