app.toml Reference
Complete reference for .miren/app.toml — the configuration file for Miren applications.
For a guide-style introduction, see App Configuration.
File Structure
name = "myapp"
post_import = "make db-migrate"
include = ["configs/"]
# Global environment variables
[[env]]
key = "DATABASE_URL"
value = "postgres://db.app.miren:5432/myapp"
# Build configuration
[build]
version = "3.12"
dockerfile = "Dockerfile.miren"
onbuild = ["npm run build"]
# Service definitions
[services.web]
command = "node server.js"
port = 3000
[services.web.concurrency]
mode = "auto"
requests_per_instance = 10
scale_down_delay = "15m"
shutdown_timeout = "10s"
[services.worker]
command = "node worker.js"
[services.worker.concurrency]
mode = "fixed"
num_instances = 2
shutdown_timeout = "10s"
[services.db]
image = "postgres:16"
[[services.db.disks]]
name = "pgdata"
mount_path = "/var/lib/postgresql/data"
size_gb = 20
# Addons
[addons.storage]
variant = "minio"
Top-Level Fields
| Field | Type | Description | Default |
|---|---|---|---|
name | string | Application name | Inferred from directory name |
post_import | string | Command to run after importing a new version (e.g. database migrations) | — |
include | string[] | Extra files or directories to include in the build context | — |
concurrency | int | Legacy. Global concurrency target. Use [services.<name>.concurrency] instead. | — |
[[env]] — Environment Variables
Declares environment variables available to all services. Service-level [[services.<name>.env]] entries are merged with these.
[[env]]
key = "DATABASE_URL"
value = "postgres://db.app.miren:5432/myapp"
[[env]]
key = "SECRET_KEY"
required = true
sensitive = true
description = "Used for session signing"
| Field | Type | Description | Default |
|---|---|---|---|
key | string | Variable name. Required. | — |
value | string | Variable value | "" |
required | bool | Fail deploy if value is empty | false |
sensitive | bool | Mask value in CLI output and logs | false |
description | string | Human-readable explanation of this variable | — |
Every env entry must have a non-empty key. If required is true and value is empty at deploy time, the deploy fails.
[build] — Build Configuration
Controls how Miren builds your container image.
[build]
version = "3.12"
dockerfile = "Dockerfile.custom"
onbuild = ["npm run build", "npm prune --production"]
alpine_image = "alpine:3.19"
| Field | Type | Description | Default |
|---|---|---|---|
version | string | Language/runtime version (e.g. "20" for Node, "3.12" for Python) | Detected from project files |
dockerfile | string | Path to a custom Dockerfile | Auto-detected (Dockerfile.miren or built-in) |
onbuild | string[] | Commands to run in /app after the main build steps | — |
alpine_image | string | Custom Alpine base image for the runtime stage | Built-in default |
[services.<name>] — Service Configuration
Each named section under services defines a process in your app. See Services for usage patterns.
[services.web]
command = "node server.js"
port = 3000
port_name = "http"
port_type = "http"
[services.postgres]
image = "postgres:16"
| Field | Type | Description | Default |
|---|---|---|---|
command | string | Command to run | Image's default entrypoint |
port | int | Port the service listens on (single-port shorthand) | 3000 (web only) |
port_name | string | Named port identifier (single-port shorthand) | Service name |
port_type | string | "http" or "tcp" (single-port shorthand) | "http" |
ports | [port] | Multi-port configuration array | — |
image | string | Container image to use instead of the app's built image | App's built image |
env | [env] | Service-specific environment variables (same schema as global [[env]]) | — |
concurrency | concurrency | Scaling configuration | See defaults below |
disks | [disk] | Persistent disk attachments | — |
You cannot mix the single-port fields (port, port_name, port_type) with the ports array on the same service.
[services.<name>.concurrency] — Scaling
Controls how many instances of a service run. See Application Scaling for tuning guidance.
Default for web: auto mode, 10 requests per instance, 15m scale-down delay, 10s shutdown timeout.
Default for all other services: fixed mode, 1 instance, 10s shutdown timeout.
# Autoscaling
[services.web.concurrency]
mode = "auto"
requests_per_instance = 10
scale_down_delay = "15m"
shutdown_timeout = "10s"
# Fixed instances
[services.worker.concurrency]
mode = "fixed"
num_instances = 2
shutdown_timeout = "10s"
| Field | Type | Description | Default |
|---|---|---|---|
mode | string | "auto" or "fixed" | "auto" for web, "fixed" for others |
requests_per_instance | int | Target concurrent requests per instance (auto mode only) | 10 |
scale_down_delay | duration | Time to wait before removing idle instances (auto mode only) | "15m" |
num_instances | int | Exact number of instances to run (fixed mode only) | 1 |
shutdown_timeout | duration | Time to wait for graceful shutdown during redeploy | "10s" |
modemust be"auto"or"fixed".- In auto mode:
requests_per_instancemust be non-negative,scale_down_delaymust be a valid Go duration, andnum_instancesmust not be set. - In fixed mode:
num_instancesmust be at least 1, andrequests_per_instance/scale_down_delaymust not be set. shutdown_timeoutmust be a valid Go duration (e.g."10s","30s").
[[services.<name>.ports]] — Ports
Configures network ports for a service. Use this when a service needs multiple ports or non-HTTP protocols. See Traffic Routing for usage patterns and examples.
[[services.app.ports]]
port = 3000
name = "http"
type = "http"
[[services.app.ports]]
port = 7000
name = "data"
type = "tcp"
node_port = 7000
| Field | Type | Description | Default |
|---|---|---|---|
port | int | Port your process listens on (1–65535). Required. | — |
name | string | Unique name for this port. Required. | — |
type | string | "http" for web traffic, "tcp" for raw TCP, "udp" for UDP | "http" |
node_port | int | Port to expose on the host machine (1–65535) | (none) |
portmust be between 1 and 65535.nameis required and must be unique within the service.typemust be"http","tcp", or"udp".- Each
(port, type)pair must be unique within the service ("tcp"and"http"share the TCP transport, so port 8080 with type"http"and port 8080 with type"tcp"conflict, but port 53 with"tcp"and port 53 with"udp"are allowed). node_portmust be between 1 and 65535 and unique across the cluster.
[[services.<name>.disks]] — Persistent Disks
Attaches persistent storage to a service. See Persistent Storage for details on local shared storage vs. Miren Disks.
[[services.db.disks]]
name = "pgdata"
mount_path = "/var/lib/postgresql/data"
size_gb = 20
filesystem = "ext4"
read_only = false
lease_timeout = "30s"
| Field | Type | Description | Default |
|---|---|---|---|
name | string | Unique disk name. Required. | — |
mount_path | string | Mount point inside the container. Required. | — |
size_gb | int | Disk size in gigabytes (required for new disks, ignored for existing) | — |
filesystem | string | "ext4", "xfs", or "btrfs" | "ext4" |
read_only | bool | Mount as read-only | false |
lease_timeout | duration | How long to wait when acquiring the exclusive disk lease | — |
nameandmount_pathare required.filesystemmust beext4,xfs, orbtrfs.size_gbmust be non-negative.lease_timeoutmust be a valid Go duration (e.g."30s","2m").- Services with disks must use
mode = "fixed"andnum_instances = 1.
[addons.<name>] — Addons
Configures add-on services managed by Miren.
[addons.storage]
variant = "minio"
| Field | Type | Description | Default |
|---|---|---|---|
variant | string | Addon variant to use | — |
Duration Format
Fields marked as duration accept Go duration strings: a sequence of decimal numbers with unit suffixes. Valid units are s (seconds), m (minutes), h (hours).
Examples: "10s", "2m", "1h30m", "15m".