2026-03-31 01:44:24 +00:00
# Appwrite
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
Self-hosted Backend-as-a-Service platform. Hybrid monolithic-microservice architecture built with PHP 8.3+ on Swoole, delivered as Docker containers.
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
## Commands
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
| Command | Purpose |
|---------|---------|
| `docker compose up -d --force-recreate --build` | Build and start all services |
| `docker compose exec appwrite test tests/e2e/Services/[Service]` | Run E2E tests for a service |
| `docker compose exec appwrite test tests/e2e/Services/[Service] --filter=[Method]` | Run a single test method |
| `docker compose exec appwrite test tests/unit/` | Run unit tests |
| `composer format` | Auto-format code (Pint, PSR-12) |
| `composer format <file>` | Format a specific file |
| `composer lint <file>` | Check formatting of a file |
| `composer analyze` | Static analysis (PHPStan level 3) |
| `composer check` | Same as `analyze` |
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
## Stack
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
- PHP 8.3+, Swoole 6.x (async runtime, replaces PHP-FPM)
- Utopia PHP framework (HTTP routing, CLI, DI, queue)
- MongoDB (default), MariaDB, MySQL, PostgreSQL (adapters via utopia-php/database)
- Redis (cache, queue, pub/sub)
- Docker + Traefik (reverse proxy)
- PHPUnit 12, Pint (PSR-12), PHPStan level 3
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
## Project layout
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
- **src/Appwrite/Platform/Modules/** -- feature modules (Account, Avatars, Compute, Console, Databases, Functions, Health, Project, Projects, Proxy, Sites, Storage, Teams, Tokens, VCS, Webhooks)
- **src/Appwrite/Platform/Workers/** -- background job workers
- **src/Appwrite/Platform/Tasks/** -- CLI tasks
- **app/init.php** -- bootstrap (registers services, resources, listeners)
- **app/init/** -- configs, constants, locales, models, registers, resources, span, database filters/formats
- **bin/** -- CLI entry points: `worker-*` (14 workers), `schedule-*` , `queue-*` , plus `doctor` , `install` , `migrate` , `realtime` , `upgrade` , `ssl` , `vars` , `maintenance` , `interval` , `specs` , `sdks` , etc.
- **tests/e2e/** -- end-to-end tests per service
- **tests/unit/** -- unit tests
- **public/** -- static assets and generated SDKs
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
## Module structure
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
Each module under `src/Appwrite/Platform/Modules/{Name}/` contains:
2025-12-19 12:09:48 +00:00
2026-03-31 01:44:24 +00:00
```
Module.php -- registers all services for the module
Services/Http.php -- registers HTTP endpoints
Services/Workers.php -- registers background workers
Services/Tasks.php -- registers CLI tasks
Http/{Service}/ -- endpoint actions (Create.php, Get.php, Update.php, Delete.php, XList.php)
Workers/ -- worker implementations
Tasks/ -- CLI task implementations
2025-12-19 12:09:48 +00:00
```
2026-03-31 01:44:24 +00:00
HTTP endpoint nesting reflects the URL path. Sub-resources get subdirectories. For example, within the Functions module:
`Http/Deployments/Template/Create.php` -> `POST /v1/functions/:functionId/deployments/template`
2026-03-06 09:42:07 +00:00
2026-03-31 01:44:24 +00:00
File names in Http directories must only be `Get.php` , `Create.php` , `Update.php` , `Delete.php` , or `XList.php` . For non-CRUD operations, model the endpoint as a property update. For example, updating a team membership status lives at `Teams/Http/Memberships/Status/Update.php` (`PATCH /v1/teams/:teamId/memberships/:membershipId/status`).
2026-03-06 09:42:07 +00:00
2026-03-31 01:44:24 +00:00
Register new modules in `src/Appwrite/Platform/Appwrite.php` . Detailed module guide: `src/Appwrite/Platform/AGENTS.md` .
2026-03-06 09:42:07 +00:00
2026-03-31 01:44:24 +00:00
## Action pattern (HTTP endpoints)
2026-03-06 09:42:07 +00:00
```php
2026-03-31 01:44:24 +00:00
class Create extends Action
{
public static function getName(): string { return 'createTeam'; }
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/teams')
->desc('Create team')
->groups(['api', 'teams'])
->label('event', 'teams.[teamId].create')
->label('scope', 'teams.write')
->param('teamId', '', new CustomId(), 'Team ID.')
->param('name', null, new Text(128), 'Team name.')
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback($this->action(...));
}
public function action(
string $teamId,
string $name,
Response $response,
Database $dbForProject,
Event $queueForEvents,
): void {
// implementation
}
}
2026-03-06 09:42:07 +00:00
```
2026-03-31 01:44:24 +00:00
Common injections: `$response` , `$request` , `$dbForProject` , `$dbForPlatform` , `$user` , `$project` , `$queueForEvents` , `$queueForMails` , `$queueForDeletes` .
## Conventions
- PSR-12 formatting enforced by Pint. PSR-4 autoloading.
- `resourceType` values are always **plural** : `'functions'` , `'sites'` , `'deployments'` .
- When updating documents, pass only changed attributes as a sparse Document:
```php
// correct
$dbForProject->updateDocument('users', $user->getId(), new Document([
'name' => $name,
]));
// incorrect -- passing full document is inefficient
$user->setAttribute('name', $name);
$dbForProject->updateDocument('users', $user->getId(), $user);
```
Exceptions: migrations, `array_merge()` with `getArrayCopy()` , updates where nearly all attributes change, complex nested relationship logic requiring full document state.
- Avoid introducing dependencies outside the `utopia-php` ecosystem.
- Never hardcode credentials -- use environment variables.
- Code changes may require container restart. No central log location -- check relevant containers.
2026-04-09 13:18:26 +00:00
## Patch release process
For bumping patch versions (e.g., `1.9.0` -> `1.9.1` ), follow the checklist in `.claude/skills/patch-release-checklist/SKILL.md` . It covers the 4 files that must be updated, console image bumps, CHANGES.md updates, and common pitfalls to avoid.
2026-03-31 01:44:24 +00:00
## Cross-repo context
Appwrite is the base server for `appwrite/cloud` . Changes to the Action pattern, module structure, DI system, or response models affect cloud. The `feat-dedicated-db` feature spans cloud, edge, and console.