# Appwrite Administration & Architecture Guide

## Executive Summary

Appwrite is a self-hosted Backend-as-a-Service (BaaS) platform built on PHP 8.3+ with Swoole 6.x for high-concurrency async I/O. It provides authentication, databases (three engines: TablesDB, DocumentsDB, VectorsDB), file storage, serverless functions, static/SSR site hosting, messaging, and real-time WebSocket subscriptions. The platform ships as a Docker Compose stack with Traefik reverse proxy, supporting MariaDB, MongoDB, or PostgreSQL as the underlying database backend. Version 1.9.1 (source commit `0aab3e9`, 2026-04-17) is the current stable release.

The codebase spans 2,763 files across two primary namespaces: `src/Appwrite/` (platform logic) and `app/` (configuration, controllers, initialization). Background processing uses a queue-driven worker architecture handling audits, certificates, deletions, function executions, mail delivery, migrations, statistics, and webhooks.

> [!IMPORTANT]
> This guide covers the self-hosted Community Edition. Appwrite Cloud may differ in configuration, scaling, and available features.

---

## 1. Architecture Overview

### 1.1 High-Level Component Map

```
Internet
  │
  ▼
Traefik (reverse proxy, auto-SSL)
  │
  ├── /v1/*    → Appwrite API (Swoole HTTP server, port 80)
  ├── /console → Console SPA
  └── Realtime → WebSocket server
  │
  ├── Redis (cache, pub/sub, queue broker)
  ├── Database (MariaDB | MongoDB | PostgreSQL)
  ├── Executor (Open Runtimes, function/site builds)
  └── Workers (10 queue consumers)
       ├── Audits        ├── Functions
       ├── Certificates  ├── Mails
       ├── Deletes       ├── Migrations
       ├── Executions    ├── StatsResources
       ├── StatsUsage    └── Webhooks
```

### 1.2 Request Lifecycle

1. Traefik terminates TLS and routes to the Swoole HTTP server.
2. The general router (`app/controllers/general.php`) resolves the project from the hostname or `X-Appwrite-Project` header.
3. Shared middleware (`app/controllers/shared/api/`) handles authentication (session, JWT, API key), rate limiting, and abuse detection.
4. Module-specific service classes (`src/Appwrite/Platform/Modules/*/Services/`) define route handlers via the `utopia-php/platform` framework.
5. Events are published to Redis queues for async processing by workers.
6. Realtime pushes changes to subscribed WebSocket clients.

### 1.3 Namespace Map

| Namespace | Purpose |
|-----------|---------|
| `Appwrite\Platform\Modules\Account` | User authentication, sessions, MFA |
| `Appwrite\Platform\Modules\Databases` | TablesDB, DocumentsDB, VectorsDB engines |
| `Appwrite\Platform\Modules\Functions` | Serverless function CRUD, deployments, executions |
| `Appwrite\Platform\Modules\Sites` | Static/SSR site hosting with framework detection |
| `Appwrite\Platform\Modules\Storage` | File buckets, uploads, previews, transformations |
| `Appwrite\Platform\Modules\Teams` | Team management, memberships, invitations |
| `Appwrite\Platform\Modules\Tokens` | Resource tokens for files, sites, functions, databases |
| `Appwrite\Platform\Modules\Webhooks` | Webhook CRUD and delivery |
| `Appwrite\Platform\Modules\Proxy` | Domain routing rules (API, function, site, redirect) |
| `Appwrite\Platform\Modules\Health` | Health checks for all subsystems |
| `Appwrite\Platform\Modules\VCS` | GitHub integration for deployments |
| `Appwrite\Platform\Modules\Console` | Admin console, redirects, assistant |
| `Appwrite\Platform\Modules\Projects` | Multi-project management, schedules |
| `Appwrite\Platform\Workers` | Queue consumer implementations |
| `Appwrite\Platform\Installer` | Web installer (Swoole server on port 20080) |
| `Appwrite\Auth` | OAuth2 base, API key validation, MFA, passphrase |
| `Appwrite\Migration` | Version migration framework (V15–V24) |
| `Appwrite\Event` | Event publishing (audit, build, certificate, database, etc.) |
| `Appwrite\GraphQL` | GraphQL endpoint, type system, promise adapters |
| `Executor\Executor` | HTTP client for Open Runtimes executor |

### 1.4 Database Architecture

Appwrite 1.8+ introduced three database engine types:

| Engine | Description | Use Case |
|--------|-------------|----------|
| **TablesDB** | Relational model with typed columns, rows, indexes | Structured data, recommended for new projects |
| **DocumentsDB** | Document-based with schemaless collections | Legacy/flexible schemas, backward-compatible |
| **VectorsDB** | Vector embeddings with similarity search | AI/ML applications, semantic search |

All three engines are backed by the same underlying database backend (MariaDB, MongoDB, or PostgreSQL) via the `utopia-php/database` abstraction layer. The engine type is set at database creation time and determines the available API surface.

> [!NOTE]
> TablesDB is the recommended engine for new projects. The Databases (DocumentsDB) service is deprecated in SDKs from version 1.8 onward but continues to work for existing data.

**Shared tables mode** — configured via `_APP_DATABASE_SHARED_TABLES` — allows multiple projects to share the same underlying database tables with tenant isolation via sequence-based partitioning.

### 1.5 Transaction Support

All three database engines support ACID transactions:

| Parameter | Value |
|-----------|-------|
| Default TTL | 300 seconds (5 minutes) |
| Minimum TTL | 60 seconds |
| Maximum TTL | 3,600 seconds (1 hour) |
| Max operations per transaction | 100 |
| Max batch size | 100 |

---

## 2. System Requirements

### 2.1 Runtime Dependencies

| Component | Requirement |
|-----------|-------------|
| PHP | >= 8.3.0 |
| Swoole | 6.x (`ext-swoole`) |
| Redis | `ext-redis` |
| ImageMagick | `ext-imagick` |
| Other PHP extensions | curl, mbstring, json, yaml, dom, pdo, openssl, zlib, sockets |

### 2.2 Key Composer Dependencies

| Package | Version | Purpose |
|---------|---------|---------|
| `utopia-php/database` | 5.x | Database abstraction (MariaDB, MongoDB, PostgreSQL) |
| `utopia-php/http` | 0.34.x | HTTP framework (Swoole adapter) |
| `utopia-php/queue` | 0.17.x | Queue broker (Redis-backed) |
| `utopia-php/storage` | 1.0.x | File storage abstraction |
| `utopia-php/cache` | 1.0.x | Cache layer (Redis pool + sharding) |
| `utopia-php/auth` | 0.5.x | Authentication primitives |
| `utopia-php/vcs` | 3.x | GitHub VCS integration |
| `utopia-php/websocket` | 1.0.x | WebSocket server |
| `webonyx/graphql-php` | 15.31.x | GraphQL execution engine |
| `appwrite/php-clamav` | 2.0.x | Antivirus scanning |
| `spomky-labs/otphp` | 11.x | TOTP for MFA |
| `adhocore/jwt` | 1.1.x | JWT token handling |
| `league/csv` | 9.14.x | CSV import/export |
| `matomo/device-detector` | 6.4.x | User-agent parsing |
| `dragonmantank/cron-expression` | 3.4.x | Cron schedule parsing |
| `enshrined/svg-sanitize` | 0.22.x | SVG file sanitization |

### 2.3 Infrastructure Requirements

| Component | Role | Minimum |
|-----------|------|---------|
| Docker + Docker Compose | Container orchestration | v20+ |
| Traefik | Reverse proxy, auto-SSL | v2+ |
| Redis | Cache, queue broker, pub/sub | 6+ |
| MariaDB / MongoDB / PostgreSQL | Primary data store | MariaDB 10.6+, MongoDB 6+, PostgreSQL 15+ |

---

## 3. Configuration Reference

### 3.1 Environment Variables

Appwrite is configured entirely via environment variables in the `.env` file. The full variable list is loaded from `app/config/variables.php` during initialization (`app/init/configs.php`).

> [!CAUTION]
> Environment variable names are prefixed with `_APP_`. Changing database-related variables on an existing installation requires careful migration. See issue [#11902](https://github.com/appwrite/appwrite/issues/11902) regarding `_APP_DB_HOST` redefinition during upgrades.

**Core variables:**

| Variable | Purpose | Default |
|----------|---------|---------|
| `_APP_ENV` | Environment mode | `development` |
| `_APP_DOMAIN` | Primary domain | — |
| `_APP_DOMAIN_TARGET` | CNAME target for custom domains | — |
| `_APP_DOMAIN_FUNCTIONS` | Functions subdomain | — |
| `_APP_DOMAIN_SITES` | Sites subdomain | — |
| `_APP_VERSION` | Reported version | `UNKNOWN` |
| `_APP_LOCALE` | Default locale | `en` |

**Database variables:**

| Variable | Purpose |
|----------|---------|
| `_APP_DB_HOST` | Database host |
| `_APP_DB_PORT` | Database port |
| `_APP_DB_USER` | Database user |
| `_APP_DB_PASS` | Database password |
| `_APP_DB_SCHEMA` | Database schema name |
| `_APP_DATABASE_SHARED_TABLES` | Comma-separated list of pool names using shared-table mode |

**Executor variables:**

| Variable | Purpose | Default |
|----------|---------|---------|
| `_APP_EXECUTOR_HOST` | Open Runtimes executor endpoint | — |
| `_APP_EXECUTOR_SECRET` | Shared secret for executor auth | — |

**Queue variables:**

| Variable | Purpose | Default |
|----------|---------|---------|
| `_APP_QUEUE_PREFETCH_COUNT` | Batch size for queue consumers | `1` |
| `_APP_AUDITS_QUEUE_NAME` | Audit queue name | `v1-audits` |
| `_APP_BUILDS_QUEUE_NAME` | Build queue name | `v1-builds` |
| `_APP_CERTIFICATES_QUEUE_NAME` | Certificate queue name | `v1-certificates` |
| `_APP_STATS_USAGE_QUEUE_NAME` | Usage stats queue name | (default in Event class) |
| `_APP_STATS_RESOURCES_QUEUE_NAME` | Resource stats queue name | (default in Event class) |

**SMTP variables:**

| Variable | Purpose |
|----------|---------|
| `_APP_SMTP_HOST` | SMTP server hostname |
| `_APP_SMTP_PORT` | SMTP port |
| `_APP_SMTP_SECURE` | TLS mode (`tls` or `ssl`) |
| `_APP_SMTP_USERNAME` | SMTP username |
| `_APP_SMTP_PASSWORD` | SMTP password |

**Logging & telemetry:**

| Variable | Purpose |
|----------|---------|
| `_APP_LOGGING_PROVIDER` | Error logging provider |
| `_APP_LOGGING_CONFIG` | Logging provider config |
| `_APP_LOGGING_SERVICE_IDENTIFIER` | Service name for logs (default: hostname) |
| `_APP_TRACE_PROJECT_ID` | Project ID for execution tracing |
| `_APP_TRACE_FUNCTION_ID` | Function ID for execution tracing |

### 3.2 Configuration Files

All configuration is loaded at startup via `app/init/configs.php`:

| Config Key | Source File | Content |
|------------|------------|---------|
| `runtimes` | `app/config/runtimes.php` | Available function runtimes (v5) |
| `runtimes-v2` | `app/config/runtimes-v2.php` | Legacy v2 runtimes |
| `events` | `app/config/events.php` | Webhook/event type definitions |
| `auth` | `app/config/auth.php` | Auth method configuration |
| `oAuthProviders` | `app/config/oAuthProviders.php` | OAuth2 provider list (40+) |
| `errors` | `app/config/errors.php` | Error code definitions (393 error types) |
| `collections` | `app/config/collections.php` | Internal database schema |
| `frameworks` | `app/config/frameworks.php` | Site framework definitions |
| `services` | `app/config/services.php` | Service registry |
| `variables` | `app/config/variables.php` | Environment variable definitions |
| `specifications` | `app/config/specifications.php` | Compute specifications |
| `cors` | `app/config/cors.php` | CORS configuration |
| `roles` | `app/config/roles.php` | User roles and scopes |
| `projectScopes` | `app/config/scopes/project.php` | Project-level scopes |
| `organizationScopes` | `app/config/scopes/organization.php` | Organization-level scopes |
| `accountScopes` | `app/config/scopes/account.php` | Account-level scopes |

### 3.3 Hard-Coded Limits

These constants are defined in `app/init/constants.php` and cannot be changed via environment variables:

| Constant | Value | Description |
|----------|-------|-------------|
| `APP_LIMIT_USERS` | 10,000 | Maximum users per project |
| `APP_LIMIT_COUNT` | 5,000 | Maximum count for list queries |
| `APP_LIMIT_LIST_DEFAULT` | 25 | Default items per page |
| `APP_LIMIT_WRITE_RATE_DEFAULT` | 60 | Max writes per rate period |
| `APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT` | 60s | Rate period duration |
| `APP_LIMIT_DATABASE_BATCH` | 100 | Max batch operation size |
| `APP_LIMIT_DATABASE_TRANSACTION` | 100 | Max operations per transaction |
| `APP_LIMIT_ANTIVIRUS` | 20 MB | Max file size for AV scanning |
| `APP_LIMIT_ENCRYPTION` | 20 MB | Max file size for encryption |
| `APP_LIMIT_COMPRESSION` | 20 MB | Max file size for compression |
| `APP_LIMIT_ARRAY_PARAMS_SIZE` | 100 | Max array parameter elements |
| `APP_LIMIT_ARRAY_LABELS_SIZE` | 1,000 | Max label array elements |
| `APP_LIMIT_SUBQUERY` | 1,000 | Max subquery results |
| `APP_LIMIT_SUBSCRIBERS_SUBQUERY` | 1,000,000 | Max subscriber subquery results |
| `APP_LIMIT_USER_PASSWORD_HISTORY` | 20 | Password history depth |
| `APP_LIMIT_USER_SESSIONS_MAX` | 100 | Max sessions per user |
| `APP_LIMIT_USER_SESSIONS_DEFAULT` | 10 | Default sessions per user |
| `APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH` | 1,073,741,824 | Max string attribute length |
| `APP_DATABASE_TIMEOUT_MILLISECONDS_API` | 15,000 ms | API query timeout |
| `APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER` | 300,000 ms | Worker query timeout |
| `APP_DATABASE_QUERY_MAX_VALUES` | 500 | Max query values (API) |
| `APP_DATABASE_QUERY_MAX_VALUES_WORKER` | 5,000 | Max query values (worker) |
| `APP_FUNCTION_LOG_LENGTH_LIMIT` | 1,000,000 | Max function log length |
| `APP_FUNCTION_ERROR_LENGTH_LIMIT` | 1,000,000 | Max function error length |
| `MAX_OUTPUT_CHUNK_SIZE` | 10 MB | Response chunk size |
| `APP_STORAGE_READ_BUFFER` | 20 MB | Storage read buffer |

### 3.4 Compute Specifications

| Constant | Value |
|----------|-------|
| `APP_COMPUTE_CPUS_DEFAULT` | 0.5 vCPU |
| `APP_COMPUTE_MEMORY_DEFAULT` | 512 MB |
| `APP_COMPUTE_SPECIFICATION_DEFAULT` | `S_1VCPU_512MB` |
| `APP_COMPUTE_DEPLOYMENT_MAX_RETENTION` | 36,500 days (~100 years) |

---

## 4. Deployment & Scaling

### 4.1 Docker Compose Stack

The production deployment uses Docker Compose with the following services:

| Service | Image | Role |
|---------|-------|------|
| `appwrite` | `appwrite/appwrite` | Main API server (Swoole) |
| `appwrite-realtime` | `appwrite/appwrite` | WebSocket server |
| `appwrite-worker-*` | `appwrite/appwrite` | Queue consumers (10 worker types) |
| `appwrite-executor` | `openruntimes/executor` | Function/site build executor |
| `traefik` | `traefik` | Reverse proxy with auto-SSL |
| `mariadb` | `mariadb` | Primary database (or mongodb/postgresql) |
| `redis` | `redis` | Cache + queue broker + pub/sub |

### 4.2 Web Installer

Appwrite includes a web-based installer (`src/Appwrite/Platform/Installer/Server.php`) that runs a Swoole HTTP server on port **20080** during initial setup or upgrades.

```bash
# Fresh install
php src/Appwrite/Platform/Installer/Server.php --docker

# Upgrade (auto-detects existing config)
php src/Appwrite/Platform/Installer/Server.php --docker --upgrade

# Clean up installer artifacts
composer installer:clean
```

The installer auto-detects upgrade mode by checking for existing `docker-compose.yml` and `.env` files. It also detects the current database backend (MariaDB, MongoDB, or PostgreSQL) from the compose file or environment variables.

**Installer steps:** env-vars → config-files → docker-compose → docker-containers → account-setup → migration → ssl-certificate.

Lock file: `/tmp/appwrite-install-lock.json`
Config file: `/tmp/appwrite-installer-config.json`
Completion marker: `/tmp/appwrite-installer-complete`

> [!WARNING]
> The installer binds to `0.0.0.0:20080` by default. Ensure this port is not publicly exposed in production. The installer enforces Content Security Policy headers and CSRF protection.

### 4.3 Storage Paths

| Constant | Path | Content |
|----------|------|---------|
| `APP_STORAGE_UPLOADS` | `/storage/uploads` | User file uploads |
| `APP_STORAGE_FUNCTIONS` | `/storage/functions` | Function deployment code |
| `APP_STORAGE_SITES` | `/storage/sites` | Site deployment files |
| `APP_STORAGE_BUILDS` | `/storage/builds` | Build artifacts |
| `APP_STORAGE_CACHE` | `/storage/cache` | File cache |
| `APP_STORAGE_CERTIFICATES` | `/storage/certificates` | SSL certificates |
| `APP_STORAGE_CONFIG` | `/storage/config` | Runtime configuration |
| `APP_STORAGE_IMPORTS` | `/storage/imports` | Temporary CSV import storage |

### 4.4 Scaling Considerations

- **Horizontal worker scaling**: Increase the number of worker containers per type. Each worker independently consumes from the Redis queue.
- **Database connection pooling**: Appwrite uses `utopia-php/pools` for connection pooling. Pool sizes are configured via connection DSNs.
- **Redis sharding**: Cache adapters support sharding across multiple Redis instances via `Utopia\Cache\Adapter\Sharding`.
- **Shared tables**: Enable `_APP_DATABASE_SHARED_TABLES` for multi-tenant deployments to reduce database count.
- **Database reconnect**: Automatic reconnect with exponential backoff — `DATABASE_RECONNECT_SLEEP = 2s`, `DATABASE_RECONNECT_MAX_ATTEMPTS = 10`.
- **Cache reconnect**: `CACHE_RECONNECT_MAX_RETRIES = 2`, `CACHE_RECONNECT_RETRY_DELAY = 1000ms`.

---

## 5. Operations

### 5.1 Worker Architecture

All background processing flows through Redis-backed queues consumed by dedicated worker processes:

| Worker | Class | Queue | Responsibility |
|--------|-------|-------|----------------|
| **Audits** | `Workers\Audits` | `v1-audits` | Batch audit log writes (60s aggregation interval) |
| **Certificates** | `Workers\Certificates` | `v1-certificates` | SSL certificate generation via Let's Encrypt, domain verification |
| **Deletes** | `Workers\Deletes` | `v1-deletes` | Cascading resource deletion (30+ deletion types) |
| **Executions** | `Workers\Executions` | `v1-executions` | Persist function execution results |
| **Functions** | `Workers\Functions` | `v1-functions` | Execute serverless functions via Open Runtimes executor |
| **Mails** | `Workers\Mails` | `v1-mails` | Send transactional emails (verification, recovery, invitation, certificate) |
| **Migrations** | `Workers\Migrations` | `v1-migrations` | Cross-instance data migration (source/destination processing) |
| **StatsResources** | `Workers\StatsResources` | configurable | Aggregate resource usage statistics |
| **StatsUsage** | `Workers\StatsUsage` | configurable | Aggregate API usage statistics |
| **Webhooks** | `Workers\Webhooks` | `v1-webhooks` | Deliver webhook HTTP calls |

> [!TIP]
> The Audits worker uses a batch aggregation pattern: it accumulates audit entries for `BATCH_AGGREGATION_INTERVAL` (60 seconds) before flushing to the database in bulk. The batch size is controlled by `_APP_QUEUE_PREFETCH_COUNT`.

### 5.2 Deletion Subsystem

The Deletes worker handles 30+ resource deletion types (all defined as `DELETE_TYPE_*` constants). Key deletion flows:

- **Project deletion**: Cascades through databases, collections, functions, sites, storage, teams, users, webhooks, and all related resources.
- **User deletion**: Removes sessions, tokens, memberships, and targets.
- **Database/collection deletion**: Removes all documents/rows, attributes, indexes, and storage.
- **Maintenance deletions**: Audit logs, abuse records, usage data, expired sessions, expired transactions, CSV exports, realtime connections.

Batch queries use a minimal select set for performance: `['$sequence', '$id', '$collection', '$permissions', '$updatedAt']`.

### 5.3 Event System

Events are published through the `Appwrite\Event` namespace using Redis queues:

| Event Class | Queue | Trigger |
|-------------|-------|---------|
| `Event\Audit` | audits | All API mutations |
| `Event\Build` | builds | Function/site deployment builds |
| `Event\Certificate` | certificates | Domain verification, SSL generation |
| `Event\Database` | databases | Attribute/index CRUD |
| `Event\Delete` | deletes | Resource deletion |
| `Event\Func` | functions | Function execution triggers |
| `Event\Mail` | mails | Transactional email |
| `Event\Realtime` | — (direct pub/sub) | WebSocket push |
| `Event\Webhook` | webhooks | Webhook delivery |

Each event class supports queue name override via environment variables (e.g., `_APP_AUDITS_QUEUE_NAME`).

### 5.4 Scheduled Tasks

Appwrite supports cron-scheduled operations for:

- **Function executions**: Schedule delayed or periodic function invocations via the `scheduledAt` parameter. Uses `dragonmantank/cron-expression` for parsing.
- **Message delivery**: Scheduled messaging via the `schedules` collection.

Schedule resource types: `execution`, `function`, `message`.

### 5.5 Health Monitoring

The Health service (`Appwrite\Platform\Modules\Health`) provides checks for:

| Endpoint Category | What It Checks |
|-------------------|----------------|
| **DB** | Database connectivity |
| **Cache** | Redis cache availability |
| **Queue** | Queue depth for all worker queues (audits, builds, certificates, databases, deletes, functions, logs, mails, messaging, migrations, stats-resources, stats-usage, webhooks, failed jobs) |
| **Storage** | Local storage device read/write |
| **Certificate** | SSL certificate validity |
| **PubSub** | Redis pub/sub connectivity |
| **AntiVirus** | ClamAV scanner availability |
| **Time** | Server time drift detection |
| **Version** | Software version reporting |
| **Stats** | System statistics |

### 5.6 Migration Framework

The migration system (`src/Appwrite/Migration/Migration.php`) manages schema upgrades across Appwrite versions:

| Version Range | Migration Class |
|---------------|-----------------|
| 1.0.0 – 1.0.3 | V15 |
| 1.1.0 – 1.1.2 | V16 |
| 1.2.x | V17 |
| 1.3.x | V18 |
| 1.4.x | V19 |
| 1.5.x | V20 |
| 1.6.x | V21 |
| 1.7.x | V22 |
| 1.8.x | V23 |
| 1.9.x | V24 |

Migrations iterate over all project documents in batches of 100, applying schema changes collection by collection.

> [!CAUTION]
> After upgrading to 1.9.0+, a missing `emailCanonical` attribute may cause errors ([#11906](https://github.com/appwrite/appwrite/issues/11906)). Ensure the migration completes successfully and verify the console database schema before serving traffic.

### 5.7 Cross-Instance Migration

The Migrations worker supports data transfer between Appwrite instances and external sources:

- **Source processing**: Reads users (password, phone), teams, databases, documents, storage files from the source.
- **Destination processing**: Writes imported data to the target instance.
- **Temporary API keys** are generated for migration operations and cleaned up afterward.
- **Resource statistics** are tracked per migration for auditing.
- **Filenames** are sanitized to prevent path traversal during import.

---

## 6. Performance

### 6.1 Database Timeouts

| Context | Timeout |
|---------|---------|
| API requests | 15 seconds (`APP_DATABASE_TIMEOUT_MILLISECONDS_API`) |
| Workers | 5 minutes (`APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER`) |
| CLI tasks | 5 minutes (`APP_DATABASE_TIMEOUT_MILLISECONDS_TASK`) |

### 6.2 Query Limits

| Context | Max Values |
|---------|------------|
| API queries | 500 (`APP_DATABASE_QUERY_MAX_VALUES`) |
| Worker queries | 5,000 (`APP_DATABASE_QUERY_MAX_VALUES_WORKER`) |

### 6.3 Rate Limiting

Default write rate limiting: **60 writes per 60-second period** per resource. Abuse detection uses `utopia-php/abuse` with time-based database-backed limiters.

### 6.4 Swoole Coroutines

The entire application runs with Swoole coroutines enabled (`SWOOLE_HOOK_ALL`), providing async I/O for database, Redis, and network operations without blocking the event loop. The CLI entry point (`app/cli.php`) also enables coroutines for worker processes.

### 6.5 Metrics & Observability

Appwrite tracks comprehensive usage metrics (defined as `METRIC_*` constants):

- **User activity**: DAU, WAU, MAU
- **Network**: requests, inbound/outbound bytes
- **Database**: reads, writes, storage per database/collection
- **Storage**: files, transformations, previews per bucket
- **Functions**: executions, compute time (MB-seconds), builds
- **Sites**: requests, inbound/outbound per site
- **Messaging**: sent/failed counts per type and provider
- **Webhooks**: sent/failed per webhook
- **Realtime**: connections, messages sent, inbound/outbound
- **Embeddings**: requests, tokens, duration, errors per model

---

## 7. Security

### 7.1 Authentication Methods

| Method | Provider Constant | Token Length |
|--------|-------------------|-------------|
| Email/password | `SESSION_PROVIDER_EMAIL` | 256 |
| Anonymous | `SESSION_PROVIDER_ANONYMOUS` | — |
| Magic URL | `SESSION_PROVIDER_MAGIC_URL` | 64 |
| Phone OTP | `SESSION_PROVIDER_PHONE` | — |
| OAuth2 (40+ providers) | `SESSION_PROVIDER_OAUTH2` | 64 |
| Server token | `SESSION_PROVIDER_SERVER` | — |
| Resource token | `SESSION_PROVIDER_TOKEN` | — |

### 7.2 Multi-Factor Authentication (MFA)

- **TOTP** via `spomky-labs/otphp` (RFC 6238)
- **Recovery codes** for backup access
- **MFA recent duration**: 30 minutes (`MFA_RECENT_DURATION = 1800`)
- Challenge/factor validation through `Account/Http/Account/MFA/` route handlers

### 7.3 API Key Types

| Type | Constant | Description |
|------|----------|-------------|
| Standard | `API_KEY_STANDARD` | Project-scoped API key |
| Dynamic | `API_KEY_DYNAMIC` | Per-request dynamic key (functions) |
| Organization | `API_KEY_ORGANIZATION` | Organization-level access |
| Account | `API_KEY_ACCOUNT` | Account-level access |

### 7.4 Token Expiration

| Token Type | Expiration |
|------------|------------|
| Login (long-lived) | 1 year (31,536,000s) |
| Login (short-lived) | 1 hour |
| Recovery | 1 hour |
| Confirmation | 1 hour |
| OTP | 15 minutes |
| Generic | 15 minutes |
| Resource token | 10 years |

### 7.5 JWT Configuration

- Algorithm: HS256 (`RESOURCE_TOKEN_ALGORITHM`)
- Max age: 10 years (`RESOURCE_TOKEN_MAX_AGE = 315,360,000s`)
- Leeway: 10 seconds (`RESOURCE_TOKEN_LEEWAY`)
- JWT library: `adhocore/jwt`

### 7.6 Activity Types

All API activity is classified for audit and abuse detection:

| Type | Constant | Description |
|------|----------|-------------|
| User | `ACTIVITY_TYPE_USER` | Authenticated user request |
| Admin | `ACTIVITY_TYPE_ADMIN` | Admin mode request |
| Guest | `ACTIVITY_TYPE_GUEST` | Unauthenticated request |
| Project key | `ACTIVITY_TYPE_KEY_PROJECT` | Project API key request |
| Account key | `ACTIVITY_TYPE_KEY_ACCOUNT` | Account API key request |
| Organization key | `ACTIVITY_TYPE_KEY_ORGANIZATION` | Organization API key request |

### 7.7 Content Security Policy

The web installer enforces strict CSP:

```
default-src 'self'; script-src 'self'; style-src 'self';
img-src 'self' data:; font-src 'self' data:; connect-src 'self';
base-uri 'none'; form-action 'self'; frame-ancestors 'none';
```

### 7.8 File Security

- **Antivirus scanning** via ClamAV (`appwrite/php-clamav`), limited to files ≤ 20 MB
- **SVG sanitization** via `enshrined/svg-sanitize`
- **Encryption** for files ≤ 20 MB at rest
- **Compression** for files ≤ 20 MB
- **Storage read buffer**: 20 MB per read operation

### 7.9 Known Security Issues

- **Command injection in function builds** via `providerRootDirectory`/`templateRootDirectory` parameters was patched ([#11929](https://github.com/appwrite/appwrite/issues/11929), CLOSED).
- **Validator state mutation**: `PersonalData::isValid` mutates internal state, causing side effects in concurrent contexts ([#11895](https://github.com/appwrite/appwrite/issues/11895), OPEN).

---

## 8. Developer Internals

### 8.1 Platform Module System

Appwrite uses the `utopia-php/platform` framework to organize functionality into modules. Each module follows this structure:

```
src/Appwrite/Platform/Modules/{Module}/
  ├── Services/          # Route registration (one class per action)
  ├── Http/              # Request/response handling
  │   └── {Resource}/    # Resource-specific endpoints
  └── Workers/           # Module-specific workers (if any)
```

Services extend `Utopia\Platform\Action` and register themselves via `Service::TYPE_HTTP`. Workers extend `Utopia\Platform\Action` with queue consumption logic.

### 8.2 Dependency Injection

The application uses `Utopia\DI\Container` for dependency injection. Key injected services (configured in `app/cli.php` and shared API init):

| Service | Type | Description |
|---------|------|-------------|
| `dbForPlatform` | `Database` | Console/platform database connection |
| `getProjectDB` | `callable` | Factory returning per-project database instances |
| `getLogsDB` | `callable` | Factory returning logs database instances |
| `publisher` | `BrokerPool` | Redis queue publisher |
| `executor` | `Executor` | Open Runtimes HTTP client |
| `cache` | `Cache` | Redis cache with sharding |
| `pools` | `Group` | Connection pool manager |
| `authorization` | `Authorization` | Auth context (disabled in CLI/worker mode) |
| `bus` | `Bus` | Event bus for cross-worker communication |
| `telemetry` | `Telemetry` | Telemetry adapter (NoTelemetry by default) |

### 8.3 Open Runtimes Executor

The `Executor` class (`src/Executor/Executor.php`) communicates with the Open Runtimes executor service via HTTP:

- **Runtime creation**: `createRuntime()` — builds and launches a container for a function deployment.
- **Execution**: Invokes function code within the runtime container.
- **Runtime migration**: Versions v3/v4 are automatically migrated to v5 (`if ($version === 'v3' || $version === 'v4') { $version = 'v5'; }`).
- **Authentication**: Bearer token via `_APP_EXECUTOR_SECRET`.
- **Addressing**: Uses `x-opr-addressing-method: anycast-efficient` for distributed executor routing.

### 8.4 GraphQL Support

Appwrite exposes a GraphQL endpoint alongside REST:

- **Parser**: `app/controllers/api/graphql.php` handles both `application/json` and `multipart/form-data` requests.
- **Type system**: `src/Appwrite/GraphQL/Types/` defines custom scalar and object types.
- **Promise adapters**: `src/Appwrite/GraphQL/Promises/Adapter/` provides async resolution.
- **Engine**: `webonyx/graphql-php` 15.31.x.

### 8.5 Realtime (WebSocket)

- WebSocket server runs as a separate container using `utopia-php/websocket`.
- Redis pub/sub distributes events to all WebSocket server instances.
- Clients subscribe to channels: `databases.{dbId}.collections.{collId}.documents`, `account`, `files`, `teams`, `functions`, etc.
- Known issue: WebSocket reconnection lacks exponential backoff ([#11939](https://github.com/appwrite/appwrite/issues/11939)).
- Metrics tracked: `METRIC_REALTIME_CONNECTIONS`, `METRIC_REALTIME_CONNECTIONS_MESSAGES_SENT`.

### 8.6 OAuth2 Framework

The abstract `Appwrite\Auth\OAuth2` class provides the base for all 40+ OAuth2 provider implementations. Each provider implements:

- `getLoginURL()` — authorization redirect URL
- `getTokens()` — exchange code for tokens
- `refreshTokens()` — token refresh
- `getUserID()`, `getUserEmail()`, `getUserName()` — user info extraction

Provider configuration is loaded from `app/config/oAuthProviders.php`.

### 8.7 SDK System

Appwrite generates client SDKs from API specifications using `appwrite/sdk-generator`. Three built-in SDK bundles are included in the repo:

| SDK | Path | Exported Services |
|-----|------|-------------------|
| Console SDK | `public/sdk-console/` | Account, Avatars, Databases, Functions, Locale, Storage, Teams |
| Project SDK | `public/sdk-project/` | Account, Avatars, Databases, Functions, Locale, Storage, Teams |
| Web SDK | `public/sdk-web/` | Account, Avatars, Databases, Functions, Locale, Storage, Teams |

All SDKs export: `Client`, `Query`, `AppwriteException`, `Permission`, `Role`, `ID`.

15+ platform SDKs are maintained separately: Web, Flutter, Android, Apple, Node.js, Python, PHP, Dart, Go, Ruby, .NET, Kotlin, Swift, Deno, Rust.

### 8.8 Agent Skills

The `docs/sdks/agent-skills/` directory contains an npm package (`appwrite/agent-skills`) following the Agent Skills Open Standard. It provides AI coding agent instructions for 9 languages: TypeScript, Python, PHP, Go, Kotlin, Swift, Ruby, .NET, and Dart. Install with:

```bash
npx skills add appwrite/agent-skills
```

### 8.9 Sites (Static/SSR Hosting)

The Sites module (`Appwrite\Platform\Modules\Sites`) supports:

- **Framework auto-detection** (Astro, Next.js, etc.) via `app/config/frameworks.php`
- **Static and SSR deployments** with build pipeline
- **Custom start commands** for SSR applications
- **Template-based deployments** from starter projects
- **VCS integration** for automatic deployments on push

### 8.10 Messaging Subsystem

Multi-channel notification delivery:

| Channel | Type Constant | Description |
|---------|---------------|-------------|
| Email | `MESSAGE_TYPE_EMAIL` | Via SMTP (`PHPMailer`) or Resend adapter |
| SMS | `MESSAGE_TYPE_SMS` | Via configured SMS provider |
| Push | `MESSAGE_TYPE_PUSH` | Push notification delivery |

Message routing: `internal` (system-generated) vs `external` (user-initiated) via `MESSAGE_SEND_TYPE_*` constants.

### 8.11 Proxy & Domain Routing

The Proxy module handles custom domain routing with these rule types:

| Rule Type | Path | Description |
|-----------|------|-------------|
| API | `Proxy/Http/Rules/API` | Route to API endpoints |
| Function | `Proxy/Http/Rules/Function` | Route to function execution |
| Site | `Proxy/Http/Rules/Site` | Route to hosted site |
| Redirect | `Proxy/Http/Rules/Redirect` | URL redirection |
| Verification | `Proxy/Http/Rules/Verification` | Domain ownership verification |

Domain rule statuses: `created` → `verifying` → `verified` (or `unverified` on failure).

---

## 9. Integration Points

### 9.1 GitHub VCS Integration

The VCS module (`Appwrite\Platform\Modules\VCS`) provides GitHub integration:

- **Repository browsing**: List repositories, branches, contents
- **Automatic deployments**: Deploy on push via GitHub webhooks
- **Framework detection**: Detect project type from repository contents
- **OAuth callback**: `VCS/Http/GitHub/Callback/` and `VCS/Http/GitHub/Authorize/`

### 9.2 Function Runtimes

Functions execute in isolated containers via Open Runtimes. Runtime environment variables available to functions:

| Variable | Description |
|----------|-------------|
| `APPWRITE_FUNCTION_ID` | Function ID |
| `APPWRITE_FUNCTION_NAME` | Function name |
| `APPWRITE_FUNCTION_DEPLOYMENT` | Active deployment ID |
| `APPWRITE_FUNCTION_PROJECT_ID` | Project ID |
| `APPWRITE_FUNCTION_RUNTIME_NAME` | Runtime name |
| `APPWRITE_FUNCTION_RUNTIME_VERSION` | Runtime version |
| `APPWRITE_FUNCTION_MEMORY` | Allocated memory |
| `APPWRITE_FUNCTION_CPUS` | Allocated vCPUs |
| `APPWRITE_VERSION` | Appwrite server version |
| `APPWRITE_REGION` | Server region |

Request headers available in function context:

| Header | Description |
|--------|-------------|
| `x-appwrite-trigger` | Trigger type (http, schedule, event) |
| `x-appwrite-event` | Event name (for event triggers) |
| `x-appwrite-user-id` | Requesting user ID |
| `x-appwrite-user-jwt` | User JWT (if authenticated) |
| `x-appwrite-execution-id` | Execution ID |
| `x-appwrite-client-ip` | Client IP address |
| `x-appwrite-key` | Dynamic API key (for server-side access) |

> [!NOTE]
> Geo information headers are not currently set for function executions ([#9581](https://github.com/appwrite/appwrite/issues/9581)).

### 9.3 Email Templates

Mail types for transactional emails:

| Type | Constant | Trigger |
|------|----------|---------|
| Verification | `MAIL_TYPE_VERIFICATION` | Email verification request |
| Magic session | `MAIL_TYPE_MAGIC_SESSION` | Magic URL login |
| Recovery | `MAIL_TYPE_RECOVERY` | Password recovery |
| Invitation | `MAIL_TYPE_INVITATION` | Team invitation |
| Certificate | `MAIL_TYPE_CERTIFICATE` | SSL certificate notifications |

Templates are loaded from `app/config/locale/templates.php` with locale-aware rendering. Known issue: session alert templates are broken for non-English locales ([#8659](https://github.com/appwrite/appwrite/issues/8659)).

### 9.4 CSV Import/Export

CSV handling uses `league/csv` 9.14.x. Known issue: CSV export may fail to complete for large datasets ([#11853](https://github.com/appwrite/appwrite/issues/11853)). Temporary import files are stored at `APP_STORAGE_IMPORTS` (`/storage/imports`).

---

## 10. Troubleshooting

### 10.1 Known Issues (from GitHub)

| Issue | Status | Description |
|-------|--------|-------------|
| [#11906](https://github.com/appwrite/appwrite/issues/11906) | OPEN | Missing `emailCanonical` attribute after 1.9.0 upgrade |
| [#11902](https://github.com/appwrite/appwrite/issues/11902) | OPEN | `_APP_DB_HOST` redefined in `.env` during upgrade |
| [#11939](https://github.com/appwrite/appwrite/issues/11939) | OPEN | WebSocket reconnection needs exponential backoff |
| [#11931](https://github.com/appwrite/appwrite/issues/11931) | OPEN | Scheduled function execution time drift |
| [#11853](https://github.com/appwrite/appwrite/issues/11853) | OPEN | CSV export failing to complete |
| [#8659](https://github.com/appwrite/appwrite/issues/8659) | OPEN | Session alert template broken for non-English |
| [#9581](https://github.com/appwrite/appwrite/issues/9581) | OPEN | Geo headers not set for function execution |
| [#11895](https://github.com/appwrite/appwrite/issues/11895) | OPEN | PersonalData validator mutates internal state |

### 10.2 Upgrade Checklist (1.8.x → 1.9.x)

1. **Backup** database and `.env` file before upgrading.
2. Run the web installer with `--upgrade` flag or update Docker images.
3. **Verify** `_APP_DB_HOST` is not redefined in `.env` ([#11902](https://github.com/appwrite/appwrite/issues/11902)).
4. **Check** that the V24 migration completed — look for `emailCanonical` attribute in the users collection ([#11906](https://github.com/appwrite/appwrite/issues/11906)).
5. **Test** OAuth2 flows if configured — redirect URIs may need updating.
6. **Monitor** scheduled function execution timing for drift ([#11931](https://github.com/appwrite/appwrite/issues/11931)).

### 10.3 Database Connection Issues

- The CLI entry point retries database connections up to 5 times with 3-second sleep intervals before failing.
- Workers and tasks use `DATABASE_RECONNECT_MAX_ATTEMPTS = 10` with `DATABASE_RECONNECT_SLEEP = 2s`.
- Log output format: `[Error] Timestamp: <ISO 8601>`, `[Error] Type:`, `[Error] Message:`, `[Error] File:`, `[Error] Line:`, `[Error] Trace:`.

---

## 11. Quick Reference

### 11.1 Development Commands

```bash
# Run tests
composer test

# Lint code
composer lint

# Format code
composer format

# Static analysis
composer analyze    # or composer check

# Benchmarks
composer bench

# Start dev installer
composer installer:dev
```

### 11.2 Key File Paths

| File | Purpose |
|------|---------|
| `app/cli.php` | CLI/worker entry point |
| `app/init/constants.php` | All application constants |
| `app/init/configs.php` | Configuration loader |
| `app/controllers/general.php` | Main request router |
| `app/controllers/shared/api/` | Shared API middleware |
| `app/config/errors.php` | Error code definitions (393 types) |
| `app/config/oAuthProviders.php` | OAuth2 provider registry |
| `app/config/variables.php` | Environment variable definitions |
| `src/Appwrite/Platform/Installer/Server.php` | Web installer |
| `src/Appwrite/Migration/Migration.php` | Version migration framework |
| `src/Executor/Executor.php` | Open Runtimes client |

### 11.3 Supported Database Backends

| Backend | Adapter | Notes |
|---------|---------|-------|
| MariaDB | `utopia-php/database` MySQL adapter | Default, most tested |
| MongoDB | `utopia-php/database` MongoDB adapter | Document-native |
| PostgreSQL | `utopia-php/database` PostgreSQL adapter | Relational alternative |

### 11.4 MongoDB Init Script

The included `mongo-init.js` reads three environment variables:

| Variable | Purpose |
|----------|---------|
| `MONGO_INITDB_USERNAME` | Initial admin username |
| `MONGO_INITDB_PASSWORD` | Initial admin password |
| `MONGO_INITDB_DATABASE` | Initial database name |

---

> [!NOTE]
> **Negative-knowledge omissions (AST extraction)**:
> - **0 CLI commands** were extracted by AST analysis. Appwrite's CLI is a PHP task runner (`app/cli.php`) that dispatches to platform action classes, not a traditional command-line tool with registered subcommands. No CLI command reference is included.
> - **0 API endpoints** were extracted by AST. Routes are registered dynamically via the `utopia-php/platform` service layer, not as static route definitions parseable by AST. API endpoint tables are not included in this guide.
> - **0 actions and 0 filters** were extracted. The platform uses dependency injection and middleware patterns rather than WordPress-style hook/filter systems.

---

_Generated May 2026 from appwrite/appwrite at 0aab3e9. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
