Ops platform / Resources
Databases
Postgres, MariaDB, libSQL or SQLite, on servers that belong to your project alone.
A database runs on a server of your project's own, never shared with another project. It is reachable only from the services of its environment, so nothing outside ops connects to it. Ops writes the connection string into a secret group; you never type a password.
Adding one
Open Databases and choose Add database:
| field | what it does |
|---|---|
| Engine | postgres (default), mariadb, libsql or sqlite |
| Write the connection string into | the secret group that receives it; not for SQLite |
| Variable | the variable name, default DATABASE_URL |
| Extensions | Postgres extensions to install |
| Keep a template for previews | Postgres and MariaDB: an idle copy previews are cloned from |
| Adopt an existing database | Postgres: name a database that already exists; ops watches it and never creates or drops it |
Ops writes the connection string into the group. Render the group, see Secrets, and the services that mount it start with it.
What each engine hands your service
For the variable DATABASE_URL:
| engine | variables in the group |
|---|---|
postgres | DATABASE_URL=postgres://<login>:<password>@<server>:5432/<database> |
mariadb | DATABASE_URL=mysql://<login>:<password>@<server>:3306/<database> |
libsql | DATABASE_URL=libsql://<server>:8080?tls=0&authToken=<token>, plus DATABASE_URL_HTTP_URL and DATABASE_URL_AUTH_TOKEN for clients that want them apart |
sqlite | none; the service that mounts it gets DATABASE_URL=sqlite://<path>/<name>.sqlite |
Every value written to the group is a secret: ops env pull names them and never shows
them. For local work, point your own DATABASE_URL at a local database.
SQLite
SQLite has no server. It is a file on a volume mounted into one service:
services: {
notes: { dockerfile: 'Dockerfile', port: 3000, volumes: [{ database: 'notes', path: '/data' }] },
},
Create the sqlite database called notes in each environment first. The service then
runs one replica, stopped before the new one starts, on the machine that holds the file,
because SQLite has one writer. A service mounts at most four databases, and each database
is mounted by one service. A preview gets its own empty one.
Templates and previews
A Postgres or MariaDB database that keeps a template has an idle copy beside it, which you fill with seed data. Each preview gets a fresh copy of the template, owned by a login of its own. Never put production data in a template: a preview runs code nobody has reviewed yet.
Rotating and restoring
The database's page lists its connection with the credential masked. Rotate sets a new password (a new token for libSQL), writes it into the group and restarts the services that use it. Restore to a point in time shows how a restore runs for its engine.
Per customer databases
A product that keeps one database per customer asks ops for them through the API, as
databases of kind tenant. They get no connection string in a group, and the Databases
page shows them as a count with a search box rather than a list.