Databases
Nanokit provides native integration with managed and containerized database engines, handling provisioning, connection string injection, branching, and environment-specific overrides.
Supported Engines
| Engine | ID | Description |
|---|---|---|
| PostgreSQL | postgres | Standard PostgreSQL — managed as a container or pointing to an existing host. |
| MySQL | mysql | Standard MySQL — managed as a container or pointing to an existing host. |
| MariaDB | mariadb | Community-driven, MySQL-compatible fork — managed as a container (mariadb:11) or existing host. Speaks the MySQL wire protocol (mysql:// URLs, port 3306). |
| MongoDB | mongo | Document database — managed as a container or MongoDB Atlas. |
| Redis | redis | In-memory key-value store — managed as a container or managed Redis. |
Planned (roadmap.v3): managed Neon (serverless PostgreSQL) and Turso (edge LibSQL) are not currently selectable engines — they are deferred pending real-account validation. The near-term, in-philosophy target (roadmap.v2) is a self-hosted libSQL (
sqld) container engine; the managed cloud paths are roadmap.v3. See Providers → Roadmap.
Property Reference
| Property | Type | Description |
|---|---|---|
engine | string | Required. Backend engine: postgres, mysql, mariadb, redis, or mongo. |
version | string | Target database version (e.g., "16", "8.0", "7.2"). Defaults to latest stable. |
plan | string | Managed service plan tier (e.g., "free", "pro", "enterprise"). Provider-specific. |
storage | string | Storage allocation (e.g., "10gb", "100gb"). For managed databases with configurable storage. |
env | object | Additional environment variables injected into the database container. |
rootPassword | string | Required (for password-protected engines). Root/Admin password for the database. There is no default — reference an env var (e.g. "${DB_PASSWORD_MAIN}", value in your git-ignored .env) or a vault:// path. |
branching | object | Configuration for isolated database copies per environment. |
Branching Properties
| Property | Type | Default | Description |
|---|---|---|---|
branching.enabled | boolean | false | Enable database branching for non-production environments. |
branching.syncData | boolean | false | Whether to copy data from the parent branch (not just schema). |
branching.parentEnv | string | "production" | The source environment to branch from. |
How Branching Works
When branching.enabled is true and the target environment is not production:
- Environment detection: Nanokit detects the active environment.
- Branch Trigger: Branching is explicit. You must provide the
--branch <name>flag tonkapp upornkapp dbcommands to activate an isolated instance. - Branch creation:
- Local Docker (Mongo/Postgres/Redis):
- Performs an Atomic Volume Clone (
cp -af) from the parent environment’s volume. - Creates a uniquely named Docker volume (e.g.,
nk-mongo-data-local_db-feat-branch). - Orchestrates a dedicated database container using the cloned volume, ensuring sub-second startup with a complete data snapshot.
- Performs an Atomic Volume Clone (
- Local Docker (Mongo/Postgres/Redis):
- Connection injection: The connection string for the new branch is automatically injected into application services.
Database URI (db://) Resolution
For maximum flexibility, services can reference databases using the db:// internal protocol.
services:
myapp:
env:
DATABASE_URL: db://main_dbAt reconciliation time, Nanokit dynamically resolves this URI into a valid connection string:
- In Production: Resolves to the production database host.
- On a Branch: Automatically resolves to the branch-specific instance (e.g.,
postgresql://user:pass@nk-project-env-main_db-branch:5432/main_db).
This avoids hardcoding branch names in your environment variables and ensures code-to-database parity during development.
Zero-Copy Strategy
Nanokit implements a Zero-Copy strategy for branching to ensure that developers have immediate access to production-like data without the wait of traditional dumps or clones.
Local (Logical Overlay)
For local development, Nanokit uses high-speed volume cloning. By leveraging an alpine helper container, Nanokit performs a recursive copy of the database data directory at the file system level. This is significantly faster than SQL dumps and ensures that every branch is completely isolated.
Cloud (Native) — planned (roadmap.v3)
Managed cloud providers (Neon Branching, Turso Database Forking) would create sub-second, zero-storage-cost snapshots via native platform APIs. This managed path is parked pending roadmap.v3 real-account validation; today, branching uses the local volume-clone strategy above.
Examples
PostgreSQL (Standard)
databases:
main_db:
engine: postgres
version: "16"MongoDB
databases:
documents:
engine: mongo
version: "7.0"
storage: "10gb"
env:
MONGO_INITDB_DATABASE: myappRedis (Cache)
databases:
cache:
engine: redis
version: "7.2"MySQL
databases:
app_db:
engine: mysql
version: "8.0"
env:
MYSQL_DATABASE: myapp
MYSQL_ROOT_PASSWORD: vault://secret/data/mysql_rootMariaDB
A MySQL-compatible fork. It reuses the MySQL machinery end-to-end — same
MYSQL_* env, port 3306, mysql:// connection URLs, in-place rotation and
mysqldump backups — only the container image differs (mariadb:11 by default,
overridable via image / version).
databases:
app_db:
engine: mariadb
version: "11" # → mariadb:11 (or set `image:` for a full override)
rootPassword: "${DB_PASSWORD_APP}" # value in your git-ignored .env
env:
MYSQL_DATABASE: myappManaged Neon / Turso — planned (roadmap.v3)
Managed Neon (serverless PostgreSQL, native zero-copy branching) and Turso
(edge LibSQL, native forking) are not selectable today. Their managed-API
integration exists but is parked pending real-account validation (roadmap.v3).
The near-term, in-philosophy target is instead a self-hosted libSQL (sqld)
container engine (roadmap.v2). See Providers → Roadmap.
AWS RDS
databases:
production_db:
engine: postgres
version: "16"
plan: db.t3.medium
storage: "100gb"
branching:
enabled: false # Standard RDS does not support zero-copy branchingPassword Rotation (Best Practice)
databases:
secure_db:
engine: postgres
# Method 1: Using Vault (Production)
rootPassword: vault://secret/db_root_password
# Method 2: Using Environment Variable (Staging/Local)
# rootPassword: ${DB_ROOT_PASSWORD}Passwords & rotation
How the password is resolved
Database passwords are not auto-generated — they are resolved deterministically from a single source, in this order:
databases.<name>.rootPasswordinnanokit.yml(a literal, or a${ENV_VAR}/env://VAR/vault://pathreference);- otherwise the
NANOKIT_DB_ROOT_PASSWORDenv var (global fallback).
There is no built-in default password: if neither source resolves, Nanokit fails fast with a clear error instead of silently using a well-known value.
That single value is both applied to the container at creation
(POSTGRES_PASSWORD / MONGO_INITDB_ROOT_PASSWORD / …) and baked into the
connection URL injected into dependent services. So you only ever set the
source — you never copy a generated password into other services by hand.
| Method | Syntax | Use case |
|---|---|---|
| Vault | rootPassword: vault://secret/path#key | Production & shared staging (max security). |
| Env var | rootPassword: "${DB_PASSWORD_MAIN}" → set DB_PASSWORD_MAIN in .env | Local / CI. |
| Direct | rootPassword: "my-complex-pass" | Simple local testing (don’t commit secrets). |
[!IMPORTANT] Never put an inline fallback in the reference (
${VAR:-somepass}commits a weak secret to git) — keep the value only in the git-ignored.env.Legacy databases created under the old
nanokit-safe-passworddefault: setNANOKIT_DB_ROOT_PASSWORD=nanokit-safe-passwordin your.envso Nanokit can keep connecting, then rotate to a real password withnkapp db rotate.
Rotating an existing password
Database engines only read the init password when the data volume is first
created — so changing the source alone does not rotate an existing DB. The
nkapp db rotate command does it safely, without data loss:
nkapp db rotate <name> -e <env> # generate a strong password
nkapp db rotate <name> --password '<value>' -e <env> # or supply your own[!IMPORTANT]
db rotatenever destroys data — it is safe to run on a live database. It only changes the credential inside the running engine (anALTER USER/changeUserPassword/CONFIG SET— never a drop or re-init) and updates the.envsource. It does not touch, delete, or recreate the data volume. The only command that wipes data is the separate, explicitnkapp destroy <name> -v(see Brand-new DB below) —rotatenever calls it.
What the command does, step by step
- Resolve the target. Loads
nanokit.yml, finds the database<name>and its engine, and computes the running container (nk-<project>-<env>-<name>). - Determine the passwords. Reads the current root password from the source
(so it can authenticate) and the new one (your
--password, or a freshly generated 32-char value). - Rotate inside the engine. Runs the change in the running container so
existing data is untouched:
- Postgres →
ALTER USER postgres WITH PASSWORD '…' - MongoDB →
db.changeUserPassword('root', '…') - Redis →
CONFIG SET requirepass …+CONFIG REWRITE - MySQL/MariaDB →
ALTER USER 'root'@'%' IDENTIFIED BY '…'; FLUSH PRIVILEGES;
- Postgres →
- Update the source. Writes the new value to the
.envvariable that backsrootPassword(parsed from its${VAR}/env://VARexpression, or theDB_PASSWORD_<NAME>convention), so the connection URL Nanokit generates will match the engine. - Report. Prints the updated
.envvariable and the next step.
Propagate to dependent services
The change above updates the database and the source, but services that are
already running still hold the old connection URL. Re-run orchestration so they
pick up the regenerated NANOKIT_DB_<NAME>_URL:
nkapp up -e <env>[!TIP] Order matters only if you rotate manually: change the engine first, then the source.
db rotatealways does both in the correct order for you.
Brand-new DB (or disposable data)
If the database has no data you need to keep, you don’t need rotate — just set
the source and recreate the volume so it re-initializes with the new password:
nkapp destroy <name> -v -e <env> # -v removes the data volume
nkapp up -e <env>[!NOTE] Managed/cloud engines (e.g. Neon — planned, roadmap.v3) would be rotated through the provider/Vault and a redeploy, not by
db rotate.
Per-Environment Database Overrides
Databases follow the same Deep Merge strategy as the rest of nanokit.yml:
databases:
main_db:
engine: postgres
branching:
enabled: true
environments:
local:
databases:
main_db:
engine: postgres # Use standard Postgres container for local dev
version: "16"
branching:
enabled: false[!TIP] Connection Injection: Nanokit automatically injects the resolved connection string into all services in the same environment via the
DATABASE_URLenvironment variable. You don’t need to manually map credentials.