stack.yaml Reference
stack.yaml Reference
A stack definition lives at .8v/stack.yaml in your project directory. It defines the services 8Vast runs, how they connect, and what resources they get.
File location
8Vast looks for stack definitions in this order:
.8v/stack/directory (split file format — one YAML per service).8v/stack.yaml.8v/stack.yml
If none exist, 8v stack up reports an error.
Top-level structure
services:
service-name:
# ... service configuration
networks:
network-name:
# ... network configuration
The file has two top-level keys: services and networks. Services are required. Networks are optional — 8Vast creates a default network if you don't define any.
Service fields
Every field available on a service definition:
services:
myservice:
image: "registry/image:tag" # OCI image (required unless build is set)
build: ./app # Build from Dockerfile (alternative to image)
command: "npm start" # Override the image's default command
cpus: 2 # CPU cores (default: 1, minimum: 1)
memory: 1024 # Memory in MB (default: 512, minimum: 128)
replicas: 3 # Number of instances (default: 1)
ports:
- "8080:80" # Port forwarding (host:container)
environment: # Environment variables
KEY: value
env_file: .env # Load variables from a file
volumes:
- "./data:/app/data" # Mount host paths into the service
networks:
- frontend # Which networks to join
healthcheck: # Health monitoring
test: "curl -f http://localhost/"
interval: 10s
timeout: 5s
retries: 3
start_period: 5s
restart: unless-stopped # Restart policy
depends_on:
- other-service # Start order and dependency
image
The OCI image to run. Use registry/image:tag format. If no tag is specified, latest is assumed.
image: postgres:15
image: redis:7-alpine
image: ghcr.io/myorg/myapp:v2.1
Every service must have either image or build (or both). If both are set, 8Vast builds the image and tags it with the image value.
build
Build an image from a Dockerfile instead of pulling one. Accepts a string (context path) or an object:
# Short form — context path, uses Dockerfile in that directory
build: ./backend
# Long form — specify context and Dockerfile separately
build:
context: ./backend
dockerfile: Dockerfile.prod
command
Override the image's default command:
command: "python manage.py runserver 0.0.0.0:8000"
cpus and memory
Resource allocation for the service.
| Field | Default | Minimum |
|---|---|---|
cpus | 1 | 1 |
memory | 512 (MB) | 128 (MB) |
cpus: 4
memory: 2048
You can also set container-level resource limits separately from the allocation:
container_cpus: 0.5 # Fractional CPU limit inside the container
container_memory: 256 # Memory limit in MB inside the container
replicas
Run multiple instances of the same service:
replicas: 3
Default is 1.
ports
Forward ports from your machine to the service. Format: "host:container".
ports:
- "8080:80" # localhost:8080 -> service port 80
- "5432:5432" # same port on both sides
- "443:443"
Each host port can only be used by one service. 8Vast rejects the configuration if two services try to use the same host port.
environment
Set environment variables. Two formats are supported:
# Map format
environment:
DATABASE_URL: postgres://localhost:5432/mydb
REDIS_URL: redis://localhost:6379
DEBUG: "true"
# List format
environment:
- DATABASE_URL=postgres://localhost:5432/mydb
- REDIS_URL=redis://localhost:6379
- DEBUG=true
Both produce the same result. Use whichever you prefer.
env_file
Load environment variables from a file. The file uses KEY=value format, one per line. Lines starting with # are comments. Empty lines are ignored.
# Single file
env_file: .env
# Multiple files
env_file:
- .env
- .env.local
Variables from env_file are loaded first. Inline environment values override them if the same key appears in both.
Example .env file:
# Database
DB_HOST=localhost
DB_PORT=5432
# App
SECRET_KEY="a-long-random-string"
Quoted values (single or double quotes) have the quotes stripped automatically.
volumes
Mount paths from your machine into the service. Format: "host:container" or "host:container:ro" for read-only.
volumes:
- "./data:/var/lib/postgresql/data" # Read-write
- "./nginx.conf:/etc/nginx/nginx.conf:ro" # Read-only
Volumes persist data across service restarts. If you stop and start a service, the data in mounted volumes is still there.
networks
Assign the service to one or more networks. Services on the same network can reach each other by name.
networks:
- frontend
- backend
If you reference a network here, it must be defined in the top-level networks section.
healthcheck
Define how 8Vast checks whether the service is healthy. A service is considered "healthy" only after its health check passes.
healthcheck:
test: "pg_isready -U postgres"
interval: 10s
timeout: 5s
retries: 3
start_period: 5s
| Field | Default | Description |
|---|---|---|
test | (required) | Command to run. Exit code 0 = healthy. |
interval | 10s | Time between checks. |
timeout | 5s | Maximum time for a single check. |
retries | 3 | Consecutive failures before marking unhealthy. |
start_period | 5s | Grace period after startup before checks count. |
The test field accepts a string (run as shell command) or a list:
# String — runs in a shell
test: "curl -f http://localhost:8080/health || exit 1"
# List with CMD-SHELL prefix
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]
Health checks matter for dependencies. When service B has depends_on: [A], B waits for A to be healthy — not just started.
restart
What to do when a service exits.
| Policy | Behavior |
|---|---|
no | Don't restart. |
always | Restart regardless of exit code. |
on-failure | Restart only if the exit code is non-zero. |
unless-stopped | Restart unless explicitly stopped. (default) |
restart: on-failure
depends_on
Declare that this service needs other services to be running (and healthy) before it starts.
depends_on:
- database
- redis
8Vast resolves the full dependency graph and starts services in the correct order. If api depends on database, and web depends on api, then the start order is: database, api, web.
Circular dependencies are rejected. If A depends on B and B depends on A, 8v stack validate catches it.
Networks
Define networks for service isolation and communication:
networks:
frontend:
driver: bridge
policy: deny
backend:
driver: bridge
subnet: 10.0.1.0/24
| Field | Default | Description |
|---|---|---|
driver | bridge | Network driver. |
policy | deny | Default traffic policy: allow or deny. |
subnet | (auto) | CIDR subnet. Auto-assigned if not specified. |
Services on the same network can communicate using service names as hostnames. Services on different networks are isolated from each other.
Validation rules
8Vast validates your stack definition before starting anything. It checks for:
- Missing image or build — every service needs one or the other.
- Port conflicts — two services can't use the same host port.
- Resource minimums — at least 1 CPU and 128 MB memory per service.
- Invalid restart policy — must be one of the four valid values.
- Undefined references — networks and dependencies must point to things that exist.
- Circular dependencies — A depends on B depends on A is rejected.
Run 8v stack validate to check without starting anything.
Defaults summary
| Field | Default value |
|---|---|
cpus | 1 |
memory | 512 MB |
replicas | 1 |
restart | unless-stopped |
healthcheck.interval | 10s |
healthcheck.timeout | 5s |
healthcheck.retries | 3 |
healthcheck.start_period | 5s |
networks[].driver | bridge |
networks[].policy | deny |