Skip to Content
ConfigurationDatabases

Databases

Nanokit provides native integration with managed and containerized database engines, handling provisioning, connection string injection, branching, and environment-specific overrides.

Supported Engines

EngineIDDescription
PostgreSQLpostgresStandard PostgreSQL — managed as a container or pointing to an existing host.
MySQLmysqlStandard MySQL — managed as a container or pointing to an existing host.
MariaDBmariadbCommunity-driven, MySQL-compatible fork — managed as a container (mariadb:11) or existing host. Speaks the MySQL wire protocol (mysql:// URLs, port 3306).
MongoDBmongoDocument database — managed as a container or MongoDB Atlas.
RedisredisIn-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

PropertyTypeDescription
enginestringRequired. Backend engine: postgres, mysql, mariadb, redis, or mongo.
versionstringTarget database version (e.g., "16", "8.0", "7.2"). Defaults to latest stable.
planstringManaged service plan tier (e.g., "free", "pro", "enterprise"). Provider-specific.
storagestringStorage allocation (e.g., "10gb", "100gb"). For managed databases with configurable storage.
envobjectAdditional environment variables injected into the database container.
rootPasswordstringRequired (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.
branchingobjectConfiguration for isolated database copies per environment.

Branching Properties

PropertyTypeDefaultDescription
branching.enabledbooleanfalseEnable database branching for non-production environments.
branching.syncDatabooleanfalseWhether to copy data from the parent branch (not just schema).
branching.parentEnvstring"production"The source environment to branch from.

How Branching Works

When branching.enabled is true and the target environment is not production:

  1. Environment detection: Nanokit detects the active environment.
  2. Branch Trigger: Branching is explicit. You must provide the --branch <name> flag to nkapp up or nkapp db commands to activate an isolated instance.
  3. 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.
  4. 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_db

At 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: myapp

Redis (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_root

MariaDB

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: myapp

Managed 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 branching

Password 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:

  1. databases.<name>.rootPassword in nanokit.yml (a literal, or a ${ENV_VAR} / env://VAR / vault://path reference);
  2. otherwise the NANOKIT_DB_ROOT_PASSWORD env 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.

MethodSyntaxUse case
VaultrootPassword: vault://secret/path#keyProduction & shared staging (max security).
Env varrootPassword: "${DB_PASSWORD_MAIN}" → set DB_PASSWORD_MAIN in .envLocal / CI.
DirectrootPassword: "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-password default: set NANOKIT_DB_ROOT_PASSWORD=nanokit-safe-password in your .env so Nanokit can keep connecting, then rotate to a real password with nkapp 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 rotate never destroys data — it is safe to run on a live database. It only changes the credential inside the running engine (an ALTER USER / changeUserPassword / CONFIG SET — never a drop or re-init) and updates the .env source. It does not touch, delete, or recreate the data volume. The only command that wipes data is the separate, explicit nkapp destroy <name> -v (see Brand-new DB below) — rotate never calls it.

What the command does, step by step

  1. Resolve the target. Loads nanokit.yml, finds the database <name> and its engine, and computes the running container (nk-<project>-<env>-<name>).
  2. 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).
  3. 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;
  4. Update the source. Writes the new value to the .env variable that backs rootPassword (parsed from its ${VAR} / env://VAR expression, or the DB_PASSWORD_<NAME> convention), so the connection URL Nanokit generates will match the engine.
  5. Report. Prints the updated .env variable 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 rotate always 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_URL environment variable. You don’t need to manually map credentials.