"How-To: Deploy to Production"

How-To: Deploy to Production

Learn how to package and deploy your Vox application using declarative environments and the vox deploy command.

You can define your deployment environment directly in your .vox files using environment blocks. This allows you to specify a base image, system packages, environment variables, exposed ports, and more.

environment staging {
    base "node:22-alpine"
    packages ["curl"]
    env STAGE = "staging"
    expose [8080]
}

[!NOTE] The npx tsx server.ts command is a legacy / opt-in Node lane. TypeScript codegen emits server.ts only when VOX_EMIT_EXPRESS_SERVER=1 is set at build time; the default product path is the generated Axum binary plus api.ts for @server fn. See vox-fullstack-artifacts.md.

Bare Metal (systemd) Provider

For applications that run directly on Linux servers without Docker, set base to "bare-metal" and Vox will generate a systemd .service file instead of a Dockerfile:

// vox:skip
environment server {
    base "bare-metal"
    workdir "/opt/my-app"
    env PORT = "8080"
    cmd ["./my-app", "--port", "8080"]
}

Running vox build will emit a server.service file ready for deployment with systemctl enable and systemctl start.

Vox will automatically use these blocks to generate customized OCI-compatible Dockerfiles or systemd service files.

1. Registry Authentication

Before pushing images to a private registry, authenticate with vox login:

# Log in to the default VoxPM registry
vox login <your-api-token>

# Log in to a private OCI registry (e.g. GitHub Container Registry)
vox login <token-or-password> --registry ghcr.io --username myuser

# Log in to Docker Hub
vox login <password> --registry registry.hub.docker.com --username myuser

Credentials are stored in ~/.vox/auth.json. When you run vox deploy, the CLI will automatically authenticate with the configured registry before pushing.

[!TIP] For CI/CD pipelines, pass the token via stdin:

echo "$REGISTRY_TOKEN" | vox login token --registry ghcr.io --username $REGISTRY_USER

2. Deploying with vox deploy

The simplest way to deploy your application is using the vox deploy command. This handles building your container image, authenticating with the registry, and pushing.

# Vox.toml
[deploy]
image_name = "my-registry.io/my-vox-app"
registry   = "my-registry.io"
runtime    = "podman"  # optional: docker or podman (auto-detected if omitted)

Then run:

vox deploy
# or for a specific environment:
vox deploy --env staging

vox deploy automatically:

  1. Detects your container runtime (Podman preferred, Docker fallback)
  2. Builds the OCI image
  3. Authenticates with your registry using credentials from vox login
  4. Tags and pushes the image

3. Manual Packaging

If you prefer building yourself, Vox generates an OCI-compatible Dockerfile:

vox package --kind docker
docker build -t my-vox-app .

4. Persistent Storage

Since Vox uses SQLite for the data layer and durability journal, ensure you mount a persistent volume if deploying as a container.

# fly.toml example
[mounts]
  source = "vox_data"
  destination = "/data"

Related Reference: