Appwrite 2.2.0. Source highlight: Appwrite 2.2 brings email policies to self-hosted installs, finishes the move of function and site executions to ClickHouse, surfaces the real reason a build failed, and folds in three weeks of fixes across auth, databases, functions, messaging and the installer. It ships with the 1.1.96 self-hosted
Check the source notes against the package and APIs you use before upgrading.
๐ Product & Engineering Leads
Use the documented changes to assess relevance to your product; release frequency alone is not a quality measure.
โ๏ธ DevOps & Security
Verify the target version, runtime requirements and rollback procedure in the official documentation.
๐ง Bug Fixes & Patches (6)
**Email policies on self-hosted.** `PATCH /v1/project/policies/deny-disposable-email`, `deny-free-email`, `deny-aliased-email` and `deny-corporate-email`, plus their entries in `GET /v1/project/policies`, now ship in the self-hosted API. The Console's Auth โ Policies โ Emails toggles work instead of returning 404. (#13641, fixes #13618)
Activity and realtime pages are usable on mobile. (appwrite/vibes#357, Console 1.1.96)
The manual deployment file picker on macOS accepts `.tar.gz` archives. (appwrite/vibes#359, Console 1.1.96)
The Twilio provider form describes the sender as a phone number or alphanumeric ID. (appwrite/vibes#344)
Impersonation shows names for recent users and remembers new picks. (appwrite/vibes#348)
OAuth2 and VCS redirect routes return JSON errors to SDK requests instead of the HTML error page. (#13625, fixes #8090)
๐ View Raw Release Notes (Original Developer Log)
Appwrite 2.2 brings email policies to self-hosted installs, finishes the move of function and site executions to ClickHouse, surfaces the real reason a build failed, and folds in three weeks of fixes across auth, databases, functions, messaging and the installer. It ships with the 1.1.96 self-hosted Console. Upgrading from 2.1.0 is a single command and a short migration on the console database.
### Highlights
- **Email policies on self-hosted.** `PATCH /v1/project/policies/deny-disposable-email`, `deny-free-email`, `deny-aliased-email` and `deny-corporate-email`, plus their entries in `GET /v1/project/policies`, now ship in the self-hosted API. The Console's Auth โ Policies โ Emails toggles work instead of returning 404. (#13641, fixes #13618)
- **Executions live in ClickHouse.** Function and site executions are written to and read from ClickHouse only; the project database copy and the `_APP_EXECUTIONS_DUAL_WRITE` flag are gone, and execution timestamps are ISO-8601 again. (#13668, #13686)
- **Build failures say why.** Orchestrator 2.2 reports the cause of a failed build (unrecognized archive, download returned 404, out of memory) and the message lands in the build logs instead of `Build failed with exit code -1.` Build durations are recorded as measured rather than capped at the timeout, and an artifact failure fails the build immediately. (#13603, #13582, #13674)
- **Alphanumeric Twilio sender IDs.** `POST /v1/messaging/providers/twilio` accepts a sender ID such as `Appwrite` in `from`, matching update, and `_APP_SMS_FROM` no longer mistakes a sender starting with `MG` for a Messaging Service SID. (#13626)
- **Console 1.1.96, self-hosted build.** Activity and realtime pages work on mobile, manual deployments on macOS can pick `.tar.gz` files, impersonation shows names for recent users, SMTP has a Resend quick setup, and `/.well-known/change-password` lets password managers deep-link to the password screen.
### Fixes
**Console**
- Activity and realtime pages are usable on mobile. (appwrite/vibes#357, Console 1.1.96)
- The manual deployment file picker on macOS accepts `.tar.gz` archives. (appwrite/vibes#359, Console 1.1.96)
- The Twilio provider form describes the sender as a phone number or alphanumeric ID. (appwrite/vibes#344)
- Impersonation shows names for recent users and remembers new picks. (appwrite/vibes#348)
**Auth and users**
- OAuth2 and VCS redirect routes return JSON errors to SDK requests instead of the HTML error page. (#13625, fixes #8090)
- A rate-limiter Redis socket shared across coroutines could crash an HTTP worker under concurrent requests. The limiter now leases its connection from a pool. (#13640)
- SMS team invitations keep `&` separators in the redirect URL so apps can read `userId` and `secret`. (#13646, fixes #8607)
- Initials avatars for handle-style names such as `@ItzNotABug` render instead of a blank square. (#13662, fixes #8042)
**Databases and TablesDB**
- Shrinking an encrypted string attribute below 150 characters on update is rejected, as it already was on create. (#13649)
- Clearing an optional attribute's default with `default: null` clears it in the stored schema, so new documents receive `null`. Point, Line and Polygon updates without `default` behave the same. (#13648, fixes #9714)
- Loading relationships no longer exceeds the configured query-value limit. (#13610, utopia-php/database 7.3.9)
- GraphQL returns array attributes as arrays, and empty arrays as `[]`, instead of objects with numeric keys. (#13627)
**Functions and Sites**
- Executions created with `X-Appwrite-JWT` receive that JWT in `x-appwrite-user-jwt`, synchronously and asynchronously. (#13647, fixes #7247)
- Domain rules are repointed before a deployment is marked active, so a site never briefly serves "No active deployments" after activation. (#13658)
**Messaging**
- Msg91 providers created without a template ID stay disabled until one is configured. (#13663)
**Installer and workers**
- The MariaDB healthcheck no longer depends on the entrypoint-managed `healthcheck` user, which made upgrades from 1.x fail with "Failed to start containers". The service also restarts unless stopped. (#13652)
- Queue consumers stop taking new jobs as soon as SIGTERM arrives, so rolling restarts drain faster. (#13629, utopia-php/queue 2.2.4)
### Under the hood
- Console notifications can name the team they belong to (`teamId`, `teamInternalId` and a `_key_team` index), applied by the V25 migration. (#13664)
- Shell commands in the builds worker, certificate issuance and migrations are built with `Utopia\Command` as argument arrays instead of concatenated strings. (#13616)
- Realtime error reporting runs on spans; the `logError` compatibility function is removed. (#13675, #13679)
- Compose orchestrator 2.1.1 โ 2.2.0, open-runtimes/sdk-for-php 2.0, autogravity 0.0.10, utopia-php/console 0.2, database 7.3.9, queue 2.2.4. (#13603, #13610, #13616, #13629, #13682, #13683)
- E2E flake fixes for the Organization and Teams suites; CI pulls MinIO from quay.io. (#13654, #13656, #13657, #13643)
### Removed
- `_APP_EXECUTIONS_DUAL_WRITE`. Executions are ClickHouse only.
- `_APP_MAINTENANCE_RETENTION_USAGE_HOURLY` and the `stats` collection it pruned. Usage has been ClickHouse only since 2.0. (#13630)
- `_APP_CONNECTIONS_DB_LOGS` and the `logs` database. Nothing read it. (#13655)
### Install
```bash
docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:2.2.0
```
### Upgrade
Upgrading from 2.1.0 uses the same command with `--entrypoint="upgrade"`, then run the migration:
```bash
cd appwrite
docker compose exec appwrite migrate
```
The migration adds two optional columns and one index to the console `notifications` collection and is quick. ClickHouse is now required for function and site executions; installs that ran 2.0.0 or 2.1.0 with dual write enabled already have their executions there, and executions that only ever existed in the project database are no longer listed. Remove `_APP_EXECUTIONS_DUAL_WRITE`, `_APP_MAINTENANCE_RETENTION_USAGE_HOURLY` and `_APP_CONNECTIONS_DB_LOGS` from your `.env` if you set them. **Back up your data first.**
### Contributors
Thank you to everyone who contributed to 2.2.0:
@ChiragAgg5k @HarshMN2345 @lohanidamodar @loks0n @Meldiron @TorstenDittmann