DocsStacks & databases
Managed database
Create a PostgreSQL, MySQL, MariaDB, Redis, Valkey, or MongoDB database per project and connect it to an application.
- Engines
- PostgreSQL · MySQL · MariaDB · Redis · Valkey · MongoDB
- Shape
- One container + volume per database
- Connect
- ${{database.<slug>.url}} in the application's env
Supported engines
| Engine | Image (default tag) | Port | Internal URL shape |
|---|---|---|---|
| PostgreSQL | postgres:16-alpine | 5432 | postgresql://app:pass@host:5432/<db> |
| MySQL | mysql:8 | 3306 | mysql://app:pass@host:3306/<db> |
| MariaDB | mariadb:11 | 3306 | mysql://app:pass@host:3306/<db> |
| Redis | redis:7-alpine | 6379 | redis://:pass@host:6379/0 |
| Valkey | valkey/valkey:8-alpine | 6379 | redis://:pass@host:6379/0 |
| MongoDB | mongo:7 | 27017 | mongodb://app:pass@host:27017/<db>?authSource=admin |
The container follows the official Docker Hub image's env vars (POSTGRES_*, MYSQL_*, MARIADB_*, --requirepass). The SQL username is always app; the database name is the slug with - replaced by _. The password is random and stored encrypted.
redis:// scheme, any Redis client is compatible).CREATE DATABASE — a new database only "exists" once it holds data. aoox writes a single placeholder document (collection _aoox_init) right after the container is ready, so the primary database shows up in the collection list (Data tab) immediately instead of only after the application's first write.PostgreSQL variants
When creating a database with Engine PostgreSQL, pick a Variant for an image with an extension preinstalled — the protocol, credentials, backups, and env references stay exactly the same as plain PostgreSQL (only the image and default tag differ). The extension is activated automatically (CREATE EXTENSION IF NOT EXISTS) as soon as the container accepts connections.
| Variant | Image (default tag) | Use case |
|---|---|---|
| pgvector | pgvector/pgvector:pg16 | Vector similarity search for embeddings (AI/ML). |
| PostGIS | postgis/postgis:16-3.4 | Geographic/spatial data types and queries. |
| TimescaleDB | timescale/timescaledb:latest-pg16 | Time-series data: hypertables, continuous aggregates. |
- No variant (default) = the plain
postgresimage, no extra extension. - Changing the variant after creation isn't supported from the dashboard — delete it and create a new one (optionally restore from a backup into the new database).
- PostGIS and TimescaleDB already activate their own extension the first time the image starts; aoox still calls
CREATE EXTENSION IF NOT EXISTSas a safety net (safe to repeat, doesn't error).
Creating a database
Project page → New database
Field Notes Name Becomes a unique slug (global, not per project). Container aoox-db-<slug>, volumeaoox_db_<slug>.Engine Pick one of the cards: PostgreSQL / MySQL / MariaDB / Redis / Valkey / MongoDB. For PostgreSQL, also pick a Variant (optional): Plain / pgvector / PostGIS / TimescaleDB. Version (image tag) A Docker Hub tag. Blank = the default for the chosen engine and variant (shown under the field and in the table above). Examples: 17,8.4,7.2.Host port Optional. Fill it in only if you need a connection from outside Docker (a laptop, a remote server). Applications on the aoox host don't need it. Listens on Defaults to This server only (127.0.0.1): the database is then not reachable from the internet and you connect through an SSH tunnel ( ssh -L 5432:127.0.0.1:5432 user@server). Choose Public only when it must be reachable from other machines, and close it in the provider firewall for everyone else: Docker-published ports are not filtered by ufw. It is chosen at creation and cannot be changed later (recreate the database).CPU / memory limit Optional; can be changed later. Wait for the running status
- 01creatingpull the image, create the volume & container, wait until the engine accepts a login (up to 2 minutes; changing mounts, limits or backups answers "still starting" meanwhile)
- 02runningready to use; credentials available
- 03stoppedcontainer stopped, data kept
- 04errorprovisioning failed — check the message
Provisioning runs in the background (the image pull can take a while); the page refreshes automatically while it's
creating.Connect it to an application
In the application's env (same project), reference it — don't copy the password:
Application envDATABASE_URL=${{database.app-db.url}}Deploy (or roll back) so the new application container picks up the value. Other forms (
host,port,username, …) are covered in Environment variables.
Connections
| Type | Host | Who can use it |
|---|---|---|
| Internal connection | aoox-db-<slug> | Containers on the aoox network: applications, compose stacks joined to that network, jobs. |
| External connection | <server-ip>:<host port> (only if a host port is set) | Laptops, GUI clients, applications on a remote server. With "This server only" the address is 127.0.0.1 and only the server itself (or an SSH tunnel) can use it; with "Public", secure it with the provider firewall. |
The Overview tab shows both, along with credentials (masked, copyable) and a ready-to-paste DATABASE_URL. Project viewers see the host, port, database, and user but never the password or the URL, and the Data tab shows table and column names without rows (Redis and Valkey: nothing, the keys are data).
Extra databases on the same server
A single PostgreSQL/MySQL/MariaDB/MongoDB container can hold several databases. On the Overview tab, next to the Connection for database selector, an owner/admin can click Add database to create a new database named [A-Za-z_][A-Za-z0-9_]*, and drop an extra database with the trash icon beside the selector (a confirmation dialog appears; everything in it is lost permanently). The one created at provisioning time is the primary one and can't be deleted. The Data tab keeps its own database selector for browsing.
REPORTS_DB_URL=${{database.app-db.url:reports}}- The host, user, and password are the same — only the database name part differs.
- The Overview tab shows a Connection for database per name when there's more than one. The add/drop buttons only show while the database is running.
- Backups have an option to include every database on the server (see Backup).
- Redis/Valkey don't have this feature (use the DB number in the URL if needed).
- MongoDB: a new database is immediately populated with a placeholder document, same as the primary one.
Operations
| Action | Where | Notes |
|---|---|---|
| Stop / Start | Database panel | Container stops; data on the volume is kept. Connected applications will error until it's started again. |
| Resource limits | Resource limits card | Applies immediately; removing a limit recreates the container (a brief restart). |
| Change version (tag) | — | Not available from the UI yet. Create a new database and restore a backup into it. |
| Engine configuration | Mount tab | Mount a file at a config path; the container is re-provisioned. |
| Delete | Database panel | With or without deleting the volume. The backup list is deleted too. With the volume (Delete with data) the volumes of its mounts (including stored config files) and the backup files on the server and their S3 copies are deleted as well; without it they are kept in the backups volume, no longer listed. |
Other tabs
- Data → Data browser: tables, queries, extra databases.
- Backup → Backup & restore: manual, schedule, retention, S3.
- Jobs → scheduled commands in the database container or a separate container from the engine image with
DB_*env — Scheduled jobs. - Mount → engine config files (
my.cnf,redis.conf) or extra volumes — Mounts. - CPU/RAM metrics (15-second samples) at the top of the panel.
Common pitfalls
| Symptom | Cause & fix |
|---|---|
| Application: connection refused / ENOTFOUND | It's using the external/localhost URL from inside a container. Use the internal URL (container name) via a reference. |
| 400 when saving env: no database "x" | The slug is wrong, or the database is in a different project. |
| Error status when creating | The image tag doesn't exist on Docker Hub, or the host port is already in use. Delete and recreate. |
| An application on a remote server can't connect | The database always runs on the aoox host. Fill in a host port + firewall, then use the external connection in the env (without a reference). |
| Data missing after deleting | It was deleted with the volume purged. Restore from a downloaded/S3 backup into a new database. |
<collection>.find({...}) (read-only — no insert/update/delete/aggregate from the query box yet; use a backup restore or the application itself to write), no Structure tab/create-collection/edit-delete row yet, and extended-JSON operators like {"$oid":"..."} aren't specially interpreted in filters yet.Next steps
Found a mistake? Edit this page on GitHub ↗