Dynamic Compose Reference
Dynamic compose is Runtipi’s app definition format for describing services, ports, volumes, and routing metadata. The preferred format is a standard docker-compose.yml file enhanced with x-runtipi metadata.
Quick Example
services:
myapp:
image: myapp:latest
volumes:
- ${APP_DATA_DIR}/data:/data
environment:
- FOO=bar
- PASSWORD=${MYAPP_PASSWORD}
x-runtipi:
is_main: true
internal_port: 80
x-runtipi:
schema_version: 2This is all you need to deploy a web app with automatic Traefik routing, networking, and data persistence.
x-runtipi Metadata Reference
Runtipi extends standard Docker Compose with x-runtipi metadata at two levels: top-level (document root) and service-level (per service).
Top-level x-runtipi
Placed at the root of docker-compose.yml, alongside services:
| Option | Type | Required | Description |
|---|---|---|---|
schema_version | number | Yes | Must be 2 |
overrides | array | No | Architecture-specific service overrides (see Architecture Overrides) |
x-runtipi:
schema_version: 2Service-level x-runtipi
Placed inside a service definition:
| Option | Type | Required | Description |
|---|---|---|---|
is_main | boolean | No | Marks this service as the main app entry point (receives Traefik routing labels) |
internal_port | number | string | No | The port the service listens on (used for Traefik routing) |
add_to_main_network | boolean | No | Adds the service to Runtipi’s shared network for cross-app communication |
services:
app:
image: myapp:latest
x-runtipi:
is_main: true
internal_port: 8080Standard Docker Compose Features
Everything else in your docker-compose.yml uses standard Docker Compose syntax. You don’t need to learn any custom format for volumes, environment variables, ports, healthchecks, etc. Here are some commonly used options:
Volumes
services:
app:
image: myapp:latest
volumes:
- ${APP_DATA_DIR}/config:/config
- ${APP_DATA_DIR}/data:/data:roUse ${APP_DATA_DIR} for app-specific persistent data and ${RUNTIPI_MEDIA_DIR} for shared media directories.
Environment Variables
services:
app:
image: myapp:latest
environment:
- TZ=${TZ}
- DB_PASSWORD=${MYAPP_DB_PASSWORD}You can reference variables defined in the app’s config.json form fields using ${VARIABLE_NAME}.
Ports
For additional ports beyond the main internal_port (which is handled by Traefik), expose them directly:
services:
app:
image: myapp:latest
ports:
- "${APP_PORT}:8080/tcp"
- "25565:25565/udp"Health Checks
services:
app:
image: myapp:latest
healthcheck:
test: curl --fail http://localhost:8080 || exit 1
interval: 30s
timeout: 10s
retries: 3
start_period: 30sDependencies
services:
app:
image: myapp:latest
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: pg_isready -U postgres
interval: 10s
timeout: 5s
retries: 5Resource Limits
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
devices:
- capabilities: [gpu]
driver: nvidia
count: 1Security Options
services:
app:
image: myapp:latest
privileged: true
cap_add:
- NET_ADMIN
cap_drop:
- ALL
security_opt:
- no-new-privileges
read_only: true
user: "1000:1000"Other Options
All standard Docker Compose options are supported, including command, entrypoint, working_dir, network_mode, extra_hosts, hostname, dns, tty, stdin_open, stop_signal, stop_grace_period, pid, sysctls, logging, devices, labels, shm_size, ulimits, and more. Refer to the Docker Compose documentation for the full specification.
Architecture Overrides
You can provide architecture-specific service overrides in the top-level x-runtipi metadata. This is useful when you need different Docker images or settings for arm64 vs amd64.
services:
media-server:
image: mediaserver:latest
volumes:
- ${APP_DATA_DIR}/config:/config
- ${RUNTIPI_MEDIA_DIR}:/media
environment:
- TZ=UTC
x-runtipi:
is_main: true
internal_port: 8096
x-runtipi:
schema_version: 2
overrides:
- architecture: arm64
services:
media-server:
image: mediaserver:arm64-latest
environment:
- ARM_SPECIFIC_VAR=enabled
- architecture: amd64
services:
media-server:
image: mediaserver:amd64-latest
deploy:
resources:
reservations:
devices:
- capabilities: [gpu]How Overrides Work
- Runtipi detects the system architecture and applies matching overrides
- Service names in overrides must match the base service names
- Only specify properties that differ per architecture
- Properties are deep-merged with the base configuration
- Array properties (like volumes or ports) in overrides replace the base arrays entirely
Supported Architectures
amd64: Standard 64-bit x86 (x86_64)arm64: 64-bit ARM (aarch64)
Complete Example
Here’s a full example of a web app with a database:
services:
app:
image: myapp:2.1.0
volumes:
- ${APP_DATA_DIR}/data:/data
environment:
- DATABASE_URL=postgresql://postgres:${MYAPP_DB_PASSWORD}@myapp-db:5432/myapp
- SECRET_KEY=${MYAPP_SECRET_KEY}
healthcheck:
test: curl --fail http://localhost:8080/health || exit 1
interval: 30s
timeout: 10s
retries: 3
depends_on:
myapp-db:
condition: service_healthy
x-runtipi:
is_main: true
internal_port: 8080
myapp-db:
image: postgres:16
volumes:
- ${APP_DATA_DIR}/db:/var/lib/postgresql/data
environment:
- POSTGRES_DB=myapp
- POSTGRES_PASSWORD=${MYAPP_DB_PASSWORD}
healthcheck:
test: pg_isready -U postgres
interval: 10s
timeout: 5s
retries: 5
x-runtipi:
schema_version: 2Legacy JSON Format (docker-compose.json)
The JSON format (docker-compose.json) is legacy and maintained for backward
compatibility only. Legacy files are automatically converted internally. New
apps should use docker-compose.yml with x-runtipi metadata as documented
above.
The legacy format uses a custom JSON structure instead of standard Docker Compose YAML. Key differences from the YAML format:
- Uses camelCase property names (
isMain,internalPort,addToMainNetwork) instead ofx-runtipimetadata - Services are an array with a
namefield instead of a map - Environment variables use
[{key, value}]array format instead ofKEY=valuestrings - Volumes use
{hostPath, containerPath}objects instead ofhost:containerstrings - Additional ports use
addPortswith{containerPort, hostPort, tcp, udp}objects
Legacy JSON Validator
You can validate legacy JSON configurations using the validator below:
Legacy Configuration Options Reference
Schema Configuration
| Option | Type | Description |
|---|---|---|
| schemaVersion | number | Schema version (must be 2) |
| services | array | Array of service configurations |
| overrides | array | Architecture-specific overrides |
Basic Configuration
| Option | Type | Description | Example |
|---|---|---|---|
| name | string (required) | The name of the service and container | "name": "nginx" |
| image | string (required) | The Docker image to use | "image": "nginx:latest" |
| command | string | string[] | The command to run in the container | "command": "/my/app" or "command": ["npm", "start"] |
| environment | array | Environment variables | [{"key": "FOO", "value": "bar"}] |
Port Configuration
| Option | Type | Description |
|---|---|---|
| internalPort | number | The main port exposed by the container |
| addPorts | array | Additional ports to expose |
Example addPorts:
"addPorts": [{
"containerPort": 8080,
"hostPort": 8080,
"tcp": true,
"udp": false,
"interface": "127.0.0.1"
}]Volume Configuration
"volumes": [{
"hostPath": "/host/path",
"containerPath": "/container/path",
"readOnly": false,
"shared": false,
"private": false,
"bind": {
"propagation": "rprivate"
}
}]Network Configuration
| Option | Type | Description |
|---|---|---|
| networkMode | string | Custom network mode |
| addToMainNetwork | boolean | Add container to main network |
| extraHosts | string[] | Additional /etc/hosts entries |
| hostname | string | Container hostname |
| dns | string | string[] | Custom DNS servers |
Health Check Configuration
"healthCheck": {
"test": "curl --fail http://localhost",
"retries": 3,
"interval": "30s",
"timeout": "10s",
"startInterval": "5s",
"startPeriod": "30s"
}Resource Configuration
| Option | Type | Description |
|---|---|---|
| deploy | object | Resource limits and reservations |
| ulimits | object | Resource limits |
| shmSize | string | Size of /dev/shm |
Security Configuration
| Option | Type | Description |
|---|---|---|
| privileged | boolean | Run container with elevated privileges |
| capAdd | string[] | Add container capabilities |
| capDrop | string[] | Drop container capabilities |
| securityOpt | string[] | Security options |
| readOnly | boolean | Mount root filesystem as read only |
| user | string | Username or UID |
Advanced Configuration
| Option | Type | Description |
|---|---|---|
| entrypoint | string | string[] | Container entrypoint |
| workingDir | string | Working directory inside container |
| tty | boolean | Allocate a pseudo-TTY |
| stdinOpen | boolean | Keep STDIN open |
| stopSignal | string | Signal to stop the container |
| stopGracePeriod | string | Time to wait to stop container |
| pid | string | PID namespace |
| sysctls | object | Sysctl settings |
| logging | object | Logging configuration |
| devices | string[] | Device mappings |
| extraLabels | object | Additional container labels |
Dependencies
| Option | Type | Description |
|---|---|---|
| dependsOn | object | string[] | Service dependencies |
| isMain | boolean | Indicates where traefik labels should be applied |
Docker Compose to Legacy JSON Converter
If you need to convert an existing docker-compose.yml to the legacy JSON format:
Docker Compose YAML
Dynamic Compose Output
The converter works for most cases, but please review the converted configuration to ensure it meets your needs. Some advanced features may not be fully supported.