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
- Traefik terminates TLS and routes to the Swoole HTTP server.
- The general router (
app/controllers/general.php) resolves the project from the hostname orX-Appwrite-Projectheader. - Shared middleware (
app/controllers/shared/api/) handles authentication (session, JWT, API key), rate limiting, and abuse detection. - Module-specific service classes (
src/Appwrite/Platform/Modules/*/Services/) define route handlers via theutopia-php/platformframework. - Events are published to Redis queues for async processing by workers.
- 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 regarding_APP_DB_HOSTredefinition 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.
# 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:20080by 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/poolsfor 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_TABLESfor 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
scheduledAtparameter. Usesdragonmantank/cron-expressionfor parsing. - Message delivery: Scheduled messaging via the
schedulescollection.
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
emailCanonicalattribute may cause errors (#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/templateRootDirectoryparameters was patched (#11929, CLOSED). - Validator state mutation:
PersonalData::isValidmutates internal state, causing side effects in concurrent contexts (#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-efficientfor distributed executor routing.
8.4 GraphQL Support
Appwrite exposes a GraphQL endpoint alongside REST:
- Parser:
app/controllers/api/graphql.phphandles bothapplication/jsonandmultipart/form-datarequests. - 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-php15.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).
- 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 URLgetTokens()— exchange code for tokensrefreshTokens()— token refreshgetUserID(),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:
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 |
|---|---|---|
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/andVCS/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).
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).
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). Temporary import files are stored at APP_STORAGE_IMPORTS (/storage/imports).
10. Troubleshooting
10.1 Known Issues (from GitHub)
| Issue | Status | Description |
|---|---|---|
| #11906 | OPEN | Missing emailCanonical attribute after 1.9.0 upgrade |
| #11902 | OPEN | _APP_DB_HOST redefined in .env during upgrade |
| #11939 | OPEN | WebSocket reconnection needs exponential backoff |
| #11931 | OPEN | Scheduled function execution time drift |
| #11853 | OPEN | CSV export failing to complete |
| #8659 | OPEN | Session alert template broken for non-English |
| #9581 | OPEN | Geo headers not set for function execution |
| #11895 | OPEN | PersonalData validator mutates internal state |
10.2 Upgrade Checklist (1.8.x → 1.9.x)
- Backup database and
.envfile before upgrading. - Run the web installer with
--upgradeflag or update Docker images. - Verify
_APP_DB_HOSTis not redefined in.env(#11902). - Check that the V24 migration completed — look for
emailCanonicalattribute in the users collection (#11906). - Test OAuth2 flows if configured — redirect URIs may need updating.
- Monitor scheduled function execution timing for drift (#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 = 10withDATABASE_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
# 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/platformservice 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.