Skip to content

Configuration

PreviewCtl is configured via a .previewctl/preview.yml file at the root of your project. This page documents every available option.

Full example

version: 1
preview:
ttl: 24h
services:
frontend:
build:
type: dockerfile
context: .
dockerfile: frontend/Dockerfile
port: 3000
env:
API_URL: http://${services.api.host}:${services.api.port}
depends_on:
- api
api:
build:
type: railpack
context: ./api
port: 8080
env:
DATABASE_HOST: ${services.postgres.host}
DATABASE_PORT: ${services.postgres.port}
REDIS_HOST: ${services.redis.host}
REDIS_PORT: ${services.redis.port}
DATABASE_URL: ${services.postgres.env.POSTGRES_URL}
STRIPE_API_KEY: ${secrets.STRIPE_API_KEY}
depends_on:
- postgres
- redis
worker:
build:
type: nixpacks
context: ./worker
env:
REDIS_HOST: ${services.redis.host}
REDIS_PORT: ${services.redis.port}
depends_on:
- redis
postgres:
image: postgres:16
port: 5432
volumes:
- /var/lib/postgresql/data
seed:
poststart:
- source: db/seed.sql
destination: /tmp/seed.sql
cmd: psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -f /tmp/seed.sql
env:
POSTGRES_DB: mydb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${Generate(16)}
POSTGRES_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${services.postgres.host}:${services.postgres.port}/${POSTGRES_DB}?sslmode=disable
redis:
image: redis:7
port: 6379

Top-level fields

FieldTypeRequiredDescription
versionintYesConfig version. Currently 1.
previewobjectNoGlobal preview settings.
servicesmapYesMap of service name to service config.

preview

FieldTypeDefaultDescription
ttlstringTime-to-live for the preview environment (e.g. 24h, 30m). Environment is cleaned up after this duration.

services.<name>

Each key under services defines a service. A service is either built from source (has build) or uses a pre-built image (has image).

FieldTypeRequiredDescription
buildobjectNo*Build configuration.
imagestringNo*Docker image to use (e.g. postgres:16).
portintNoPort the service listens on inside the container.
envmapNoEnvironment variables. Values support template syntax.
volumesstring[]NoContainer volume mounts.
seedobjectNoSeed configuration for initializing the container with files and commands.
depends_onstring[]NoServices this service depends on. Controls startup order.

* One of build or image is required.

services.<name>.build

FieldTypeRequiredDescription
typestringYesBuild type: dockerfile, nixpacks, or railpack.
contextstringYesBuild context path, relative to the project root.
dockerfilestringNoPath to Dockerfile (only for type: dockerfile). Relative to context.

Build types

TypeDescription
dockerfileStandard Docker build. Specify context and optionally dockerfile.
nixpacksAutomatic build using Nixpacks. Detects language and framework.
railpackAutomatic build using Railpack.

services.<name>.seed

The seed field lets you copy files into a container and optionally run initialization commands. This is useful for database seeding, loading fixtures, or running migrations.

FieldTypeRequiredDescription
prestartSeedEntry[]NoFiles to copy into the container before it starts. No commands can be run.
poststartSeedEntry[]NoFiles to copy and commands to run after the container starts and is healthy.

Seed entry fields

FieldTypeRequiredDescription
sourcestringYesPath to the file or directory on the host, relative to the project root.
destinationstringYesPath inside the container where the file will be copied.
cmdstringNoCommand to run inside the container after copying (only for poststart).

Example: Database seeding

services:
postgres:
image: postgres:16
port: 5432
seed:
poststart:
- source: db/seed.sql
destination: /tmp/seed.sql
cmd: psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -f /tmp/seed.sql
env:
POSTGRES_DB: mydb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${Generate(16)}

Example: Config file injection

services:
nginx:
image: nginx:latest
port: 80
seed:
prestart:
- source: config/nginx.conf
destination: /etc/nginx/nginx.conf

How seeding works

  1. Prestart seeds run after the container is created but before it starts. Files are copied into the stopped container. This is ideal for configuration files that must be in place before the process launches.
  2. Poststart seeds run after the container starts and is healthy. Files are copied first, then the optional cmd is executed inside the container via sh -c. This is ideal for database initialization, running migrations, or loading fixtures.

Template syntax

Environment variable values support template expressions:

TemplateDescriptionExample
${services.<name>.host}Hostname of another service${services.postgres.host}
${services.<name>.port}Port of another service${services.api.port}
${services.<name>.env.<VAR>}Env var from another service${services.postgres.env.POSTGRES_URL}
${secrets.<KEY>}Injected secret${secrets.STRIPE_API_KEY}
${Generate(n)}Random string of length n${Generate(16)}
${<VAR>}Self-reference to own env var${POSTGRES_USER}

Secrets

Secrets referenced with ${secrets.<KEY>} are provided at runtime via:

Terminal window
# Inline
previewctl up --secret STRIPE_API_KEY=sk_test_abc123
# From file
previewctl up --env-file .env