DinD HostingManual
CHAPTER 08

Databases

A database is a container in a database daemon, with generated credentials. Your app reaches it over the platform's private network; you reach it through the SQL console.

Creating a database#

Open the project's Databases tab, press + add database, choose a name and an engine — postgres or mysql — and press create.

hosting.example.com/projects/7
Databases
The Databases tab. (1) one row per database with its engine and image, (2) the endpoint and credentials' user, (3) the SQL console and drop buttons.

The password is shown once, in the database created dialog. Copy it now — the platform stores it encrypted and never displays it again (the app receives it as a variable).

bash
curl -fsS -X POST "$BASE/api/v1/projects/$PID/databases" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"engine":"postgres","name":"main"}'
create_database(project=7, name="main", engine="postgres")

The response contains the credentials and the image the database runs. The password is only in this response.

PostgreSQL MySQL
Image for a new database postgres:17-alpine mysql:8.4
Healthcheck pg_isready mysqladmin ping
Dump format pg_dump -Fc (.pgdump) mysqldump --single-transaction --routines --triggers (.sql.gz)

Names: a letter first, then lowercase letters, digits and hyphens. The console accepts 2–21 characters (the API allows underscores and up to 40).

A database keeps the image it was created from

Each database stores its image for life. A Postgres 16 database stays on 16 — a 16 data directory will not start under 17 — also when it is recreated for a restore. Moving to a newer major is a dump and restore into a new database. The image is shown next to the engine in the console.

Where a database lives#

Databases run in a database daemon, not in your app daemon. By default that is the one shared db daemon; an administrator can give a user a dedicated db-<alias> daemon. Either way every database is its own container with its own volume (dbdata-<slug>-<name>), port (20000–29999) and credentials, reachable only on the platform's internal network — there is no public database port.

Connecting your app#

List the database in platform.yaml and the platform injects five variables, with the name upper-cased:

platform.yaml
databases: [main]
Variable Example
DB_MAIN_HOST 172.28.0.10
DB_MAIN_PORT 20000
DB_MAIN_USER generated
DB_MAIN_PASSWORD generated, never shown in the console
DB_MAIN_NAME the database name
js
import pg from "pg";
const pool = new pg.Pool({
  host: process.env.DB_MAIN_HOST, port: +process.env.DB_MAIN_PORT,
  user: process.env.DB_MAIN_USER, password: process.env.DB_MAIN_PASSWORD,
  database: process.env.DB_MAIN_NAME,
});
python
import os, psycopg

conn = psycopg.connect(
    host=os.environ["DB_MAIN_HOST"], port=os.environ["DB_MAIN_PORT"],
    user=os.environ["DB_MAIN_USER"], password=os.environ["DB_MAIN_PASSWORD"],
    dbname=os.environ["DB_MAIN_NAME"],
)
php
$dsn = sprintf("pgsql:host=%s;port=%s;dbname=%s",
  getenv("DB_MAIN_HOST"), getenv("DB_MAIN_PORT"), getenv("DB_MAIN_NAME"));
$pdo = new PDO($dsn, getenv("DB_MAIN_USER"), getenv("DB_MAIN_PASSWORD"));

Order matters

The variables are injected only for databases that exist when the app is deployed or recreated. Create the database first, then deploy — or press recreate on the App tab afterwards. Prefer database names without hyphens: a name such as my-db produces DB_MY-DB_HOST, which a shell cannot read.

The SQL console#

Press sql console on a database row. It runs one statement as the project's database user and shows the result as a table.

hosting.example.com/projects/7
SQL console — main
The SQL console: a text area, run, and create dump. The result shows the row count and the time taken.

Guardrails, identical in the console and the MCP tool run_query:

Guardrail Value
Statements per call one
Timeout 30 s by default (statement_timeout / max_execution_time)
Result size truncated at 1 000 rows or 1 MiB, and marked as truncated
Audit every execution is written to the query log with user, SQL, status, rows and duration

For schema work, use your migrations

The console is for looking and quick fixes. Run schema changes from your app's migration tool on startup, so a restore or a fresh database comes up consistent.

Dumps#

create dump (or dump_database) writes a compressed logical dump to MinIO and lists it under latest dumps with its size and sha256. The dump runs in a temporary container created from the database's own image, so the tool version always matches the server. Dumps follow the backup retention policy — see Backups & restore.

Dropping a database#

drop removes the container and its volume. Dumps already stored in MinIO are the only way back — take one first.