# Appwrite Console: the Svelte web UI you self-host alongside Appwrite

> Appwrite Console is the browser interface for an Appwrite instance, built with Svelte and SvelteKit and shipped as a Docker image behind nginx. It is worth knowing what it expects from its environment before you point it at your own deployment.

**appwrite/console** — The Console that makes Appwrite tick from the browser  🖥

- Repository: https://github.com/appwrite/console
- Website: https://appwrite.io
- Stars: 394 · Forks: 261
- Language: Svelte
- License: BSD-3-Clause
- Published: 2026-08-24 · Updated: 2026-08-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/appwrite-console

## What problem Appwrite Console solves, and for whom

Appwrite is a backend platform. Without a graphical layer, every collection, user, function and storage bucket has to be managed through API calls or a command line. Appwrite Console is that graphical layer: the README describes it as "the Graphical User Interface that developers interact with when accessing their Appwrite instance in the web browser." Its audience is therefore narrow and specific. You are running an Appwrite instance, self-hosted or otherwise, and you want to click through users, databases and settings instead of scripting each change. The README also frames the project as an answer to its own earlier UI: Console 2.0 is built on Svelte and SvelteKit rather than an in-house library, and the stated reason is contribution. Svelte is better documented and better known, so outside developers can read the code and send patches. If you are evaluating this repository as a general-purpose admin dashboard, stop here. It is not one, and the environment file makes that clear: the only backend it knows how to talk to is an Appwrite endpoint.

## How the console is wired: SvelteKit, build-time env, nginx

The repository layout tells most of the story. src/ holds the SvelteKit application, static/ holds static assets, and build.js drives the production build through the package.json script "build": "bun run build.js". The Dockerfile is a two-stage build. The first stage starts from oven/bun:alpine, copies package.json and bun.lock, and runs bun install --frozen-lockfile, then copies build.js, tsconfig.json, svelte.config.js, vite.config.ts, src and static before running bun run build. The second stage is nginx:1.29.5-alpine, which copies docker/nginx.conf into the nginx config directory and the build output into /usr/share/nginx/html/console.

The configuration model is the part that catches people out. The Dockerfile declares PUBLIC_APPWRITE_ENDPOINT, PUBLIC_CONSOLE_MODE, PUBLIC_CONSOLE_FEATURE_FLAGS, PUBLIC_APPWRITE_MULTI_REGION, PUBLIC_GROWTH_ENDPOINT, PUBLIC_STRIPE_KEY, PUBLIC_CONSOLE_FINGERPRINT_KEY, PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS, SENTRY_AUTH_TOKEN and SENTRY_RELEASE as build arguments, and then sets them as environment variables inside the build stage. Because these are consumed during bun run build rather than at container start, changing the Appwrite endpoint means rebuilding the image, not restarting the container with a new value. The compose.yml file mirrors this: the same values are passed under build.args, and the runtime environment block lists only PUBLIC_CONSOLE_MODE, PUBLIC_CONSOLE_FEATURE_FLAGS, PUBLIC_APPWRITE_MULTI_REGION, PUBLIC_APPWRITE_ENDPOINT, PUBLIC_GROWTH_ENDPOINT and PUBLIC_STRIPE_KEY. The Dockerfile also sets NODE_OPTIONS=--max_old_space_size=8192, which is a plain admission that the build is memory-hungry.

## Running the console with Docker Compose

The repository ships a compose.yml and a .env.example, and the intended local flow starts from the example environment file, which sets PUBLIC_CONSOLE_MODE to self-hosted, PUBLIC_APPWRITE_ENDPOINT to http://localhost/v1, PUBLIC_APPWRITE_MULTI_REGION to false, and PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS to true. The compose file builds the image from the local Dockerfile, passes the environment values as build arguments, and publishes port 3000 on the host mapped to port 80 inside the container, where nginx listens.

```yaml
services:
    console:
        image: appwrite/console:dev
        build:
            context: .
        ports:
            - '3000:80'
```

Bring the service up with docker compose up --build. After the build finishes, the console is reachable at http://localhost:3000. If the page loads but cannot reach a backend, the endpoint value is the first thing to check: PUBLIC_APPWRITE_ENDPOINT is compiled into the bundle, so editing the environment file and restarting the container alone will not change it. The compose file also defines a develop.watch block that rebuilds on changes under ./ while ignoring .github, tests/, node_modules/ and build/.

## Working on the console source directly

Contributing or debugging the UI does not require Docker. The package.json scripts assume bun as the package manager, and the lockfile in the repository is bun.lock.

```json
"scripts": {
    "dev": "vite dev",
    "build": "bun run build.js",
    "preview": "vite preview",
    "prepare": "svelte-kit sync || echo ''",
    "clean": "rm -rf node_modules && rm -rf .svelte-kit && bun install",
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
    "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
    "format": "prettier --write --cache .",
    "lint": "prettier --check . && eslint .",
    "tests": "bun run test:unit && bun run test:e2e",
    "test:unit": "TZ=EST vitest run",
    "test:e2e": "playwright test"
}
```

The dev script is "vite dev", and the build script is "bun run build.js", so the two paths are not identical. For checking types, the repository provides "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json". Testing is split in two: "test:unit": "TZ=EST vitest run" for unit tests and "test:e2e": "playwright test" for end-to-end tests against a real browser. Note the timezone pin on the unit tests, which suggests date handling is a known source of flakiness. The README states that all code contributions, including those from people with commit access, must go through a pull request approved by a core developer before merging, so the local workflow is only the first half of the process.

## Where the console is the wrong tool

The clearest limitation is the build-time configuration. Anything that varies between deployments has to be known when the image is built, which sits awkwardly with the usual practice of building one artifact and promoting it across environments. If you run several Appwrite instances, you are looking at one console image per endpoint, or a rebuild step in your pipeline.

The second constraint is scope. This is a front end. It has no database, no scheduler and no API of its own beyond what SvelteKit serves, and it depends on the @appwrite.io/console package for talking to Appwrite. Point it at nothing and it renders a shell that cannot do anything useful.

The third is the AI surface. The Dockerfile exposes PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS, and the example environment file sets it to true. That default is a mock, not a working assistant, and the repository does not document what a production value looks like.

Finally, the build is heavy. The Dockerfile raises the Node heap to 8192 MB, and the dependency list is long, spanning CodeMirror packages, Stripe, Sentry and Plausible analytics. On a small CI runner, expect the build to be the slow part of the pipeline. The README does not document rollback, version pinning against a specific Appwrite server release, or what happens when console and server versions drift apart.

## Alternatives and how they differ

The obvious alternative is the Appwrite API itself, through an SDK or plain HTTP. That is not a competitor in the product sense; it is the same backend without the UI layer. The difference in approach matters when you need repeatable operations: a script that creates a collection is reviewable, diffable and idempotent, while a sequence of clicks in the console is none of those. Teams that manage many Appwrite projects often keep the console for inspection and use the API for provisioning.

A second alternative is a general-purpose admin panel pointed at Appwrite's REST API. Those tools assume they can discover your schema at runtime and that configuration lives in a database or a config file. Appwrite Console does not work that way: it is compiled against a fixed set of public environment values and a specific SDK build, which is why it can offer a tailored interface for Appwrite concepts like functions and buckets but cannot be retargeted at another backend. If your requirement is one dashboard across several different services, this project is the wrong shape.

## Licence and the cost of staying current

The repository is available under the BSD 3-Clause License, per the README and the LICENSE file at the top level. That is a permissive licence, so redistribution and modification are allowed subject to its conditions; reading the LICENSE file is the right move before you ship a modified image, and this article is not legal advice. The practical maintenance cost is the build pipeline rather than the licence. The last push to the repository was on 2026-08-27, the same day as the 8.8.5 release, with 8.8.4 and 8.8.3 landing two days earlier. Releases are frequent, and because the console talks to a specific Appwrite server version, upgrading one side without the other is the risk to plan for. Pinning to a release tag and rebuilding on your own schedule is more predictable than tracking main.

## Conclusion

Adopt Appwrite Console if you already run Appwrite and want the official browser interface rather than driving the API by hand, or if you are contributing UI changes through a pull request. Do not adopt it as a standalone admin panel for some other backend: it is the front end for an Appwrite instance and needs PUBLIC_APPWRITE_ENDPOINT to point at one. Before deploying, verify the endpoint value your build receives, since PUBLIC_APPWRITE_ENDPOINT is baked in at image build time rather than read at container start.

## FAQ

### How do I install and run Appwrite Console?

The repository ships a compose.yml and a .env.example, and the compose file builds the image from the local Dockerfile and publishes port 3000 on the host, mapped to port 80 inside the container where nginx serves the built files. Fill in the public values in the environment file before starting the service.

### Can I change the Appwrite endpoint without rebuilding the Appwrite Console image?

No. The Dockerfile declares PUBLIC_APPWRITE_ENDPOINT as a build argument and sets it as an environment variable inside the build stage, so the value is consumed during bun run build. Changing it requires rebuilding the image, not just restarting the container with a new value.

### What frameworks is Appwrite Console built with?

The README lists Svelte and SvelteKit. It also states that Console 2.0 uses Svelte instead of the project's own library, on the grounds that Svelte is better documented and better known, which makes community contributions easier.

### What licence does Appwrite Console use?

The repository is available under the BSD 3-Clause License, according to the README and the LICENSE file at the top level of the repository.

## Sources

- [Official documentation](https://appwrite.io)
- [Official README](https://github.com/appwrite/console#readme)
- [Project repository](https://github.com/appwrite/console)
- [Release notes](https://github.com/appwrite/console/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/appwrite-console
