Skip to main content

Stack JSON Reference

The stack.json file is the core of every Swisblade project. It defines your services, their dependencies, and how they connect. Place it at the root of your repository.

Format

{
"name": "my-project",
"services": {
"service-name": {
"type": "app",
"source": { "repo": "github.com/you/repo.git", "ref": "main" },
"runtime": "node",
"port": 3000,
"public": true,
"needs": ["postgres", "redis"],
"connects_to": ["worker"],
"requires_env": ["API_KEY", "STRIPE_SECRET"]
}
}
}

Top-level fields

FieldTypeRequiredDescription
namestringYesProject name. Used for display and slug generation.
versionnumberNoSchema version (for future use).
servicesobjectYesMap of service name → service definition.

Service definition

Each key in services is a service name (used for DNS, env var names, and logging). Service names should be lowercase alphanumeric with hyphens.

Common fields

FieldTypeDefaultDescription
typestring"app", "custom", or "database". Required.
portnumberInternal port the service listens on.
connects_tostring[][]Other services this one communicates with.
requires_envstring[][]Env vars that must exist in the vault before deploying. Optional.

App services (type: "app")

Application services are built from your source code.

FieldTypeRequiredDescription
sourceobjectYes{ repo, ref } for git repos, or { path } for local/monorepo.
source.repostringGit repository URL (e.g., github.com/you/api.git). Required for git source.
source.refstringBranch, tag, or commit SHA to deploy. Required for git source.
source.pathstringRelative path to the service directory. Required for local source.
runtimestringYes"node", "python", or "java". Used for auto-instrumentation.
portnumberYesPort your application listens on inside the container.
publicbooleanNoExpose this service with a public HTTPS URL.
needsstring[]NoShared infrastructure to provision. See needs.
requires_envstring[]NoEnv var names the service requires. Validated against the vault before deploy.
authobjectNoPut a login in front of this service. See Authentication.
custom_domainstringNoServe this service on your own domain, alongside the free URL. See Custom Domains. Requires public: true.
imagestringNoOverride: use this Docker image instead of building.

Custom services (type: "custom")

Pre-built Docker images (e.g., RabbitMQ, Elasticsearch).

FieldTypeRequiredDescription
imagestringYesDocker image (e.g., rabbitmq:3-management).
portnumberNoInternal port.
protocolstringNoProtocol for URL generation (default: "http").
versionstringNoImage version tag.

Database services (type: "database")

Named database services run on the shared platform infrastructure with their own credentials. Use them when a service needs a separate database (e.g., an analytics DB distinct from the main one).

FieldTypeRequiredDescription
enginestringYes"postgres" or "mysql".
{
"analytics-db": {
"type": "database",
"engine": "mysql"
}
}

App services connect to database services via connects_to. The injected env var follows the pattern DATABASE_URL_{NAME}:

{
"worker": {
"type": "app",
"connects_to": ["analytics-db"]
}
}

This injects DATABASE_URL_ANALYTICS_DB=mysql://proj_xxx_analytics_db:password@platform-mysql:3306/proj_xxx_analytics_db.

Each named database gets its own user and schema, isolated from the default database provisioned by needs.

note

Named databases count toward your plan's database limit. The free tier allows 2 databases per stack (including the default one from needs).

needs

The needs array declares shared infrastructure that Swisblade provisions and manages for you. Connection credentials are injected automatically.

"needs": ["postgres", "redis", "rabbitmq"]
ValueWhat you getEnv var injected
"postgres"PostgreSQL 16 database with dedicated userDATABASE_URL
"mysql"MySQL 8 database with dedicated userDATABASE_URL
"redis"Redis 7 with isolated key prefixREDIS_URL + REDIS_KEY_PREFIX
"rabbitmq"RabbitMQ vhost with dedicated userMQ_URL

Each service gets its own credentials, isolated from other projects. You can also use the object form for custom naming:

"needs": [{ "type": "postgres", "name": "analytics-db" }]

connects_to

Declares service-to-service communication within the same project. Swisblade injects the target service's internal URL as an environment variable.

{
"api": {
"type": "app",
"connects_to": ["worker", "notifications"]
}
}

This injects:

  • WORKER_URL=http://worker:8080
  • NOTIFICATIONS_URL=http://notifications:3000

The URLs use Docker's internal DNS — services can reach each other by name within the same project.

When connects_to points to a type: "database" service, a connection string is injected instead:

{
"api": { "type": "app", "connects_to": ["analytics-db"] },
"analytics-db": { "type": "database", "engine": "postgres" }
}

This injects DATABASE_URL_ANALYTICS_DB=postgresql://... with dedicated credentials.

requires_env

Optional pre-deploy validation. Lists environment variable names that must exist in the project vault before the deploy starts. If any are missing, the deploy fails immediately with a clear error.

"requires_env": ["STRIPE_KEY", "WEBHOOK_SECRET"]

All variables stored in the vault are automatically injected into every service at deploy time — you don't need to declare them in stack.json. The requires_env field is a safety net: it ensures critical variables are present before your containers start.

If you don't declare requires_env, the deploy proceeds without checking. If a variable is missing, your application will fail at runtime instead of at deploy time.

See Environment Variables for details on managing the vault.

Full example

A multi-service project with an API, worker, named database, cache, and message queue:

{
"name": "ecommerce",
"services": {
"api": {
"source": { "repo": "github.com/myorg/api.git", "ref": "v2.1.0" },
"type": "app",
"runtime": "java",
"port": 3000,
"public": true,
"needs": ["postgres", "redis"],
"connects_to": ["worker"],
"requires_env": ["STRIPE_KEY", "WEBHOOK_SECRET"]
},
"worker": {
"source": { "repo": "github.com/myorg/worker.git", "ref": "v1.4.0" },
"type": "app",
"runtime": "node",
"port": 8080,
"needs": ["rabbitmq"],
"connects_to": ["analytics-db"]
},
"analytics-db": {
"type": "database",
"engine": "mysql"
}
}
}

Monorepo example

If all your services live in a single repository, use source.path instead of source.repo:

{
"name": "monorepo-app",
"services": {
"api": {
"source": { "path": "packages/api" },
"type": "app",
"runtime": "java",
"port": 3000,
"public": true,
"needs": ["postgres"]
},
"worker": {
"source": { "path": "packages/worker" },
"type": "app",
"runtime": "java",
"port": 3000,
"needs": ["rabbitmq"]
}
}
}

Each path is relative to the project root. Each service directory must contain its own Dockerfile (or be auto-detectable by Nixpacks).

Visual Builder NEW

Don't want to write JSON by hand? Use the Visual Builder in the Create Project dialog. It lets you:

  • Add app services (pick runtime, port, git repo)
  • Add containers (specify a Docker image directly)
  • Add database services (PostgreSQL or MySQL)
  • Toggle infrastructure needs (Postgres, MySQL, Redis, RabbitMQ) with optional custom names
  • Connect services via connects_to
  • Declare required env vars (requires_env) for pre-deploy validation
  • Toggle public access per service

The builder shows your plan limits in real time (services and databases per stack) and validates your configuration as you go. It generates the exact same stack.json that you would write manually — no features are lost.

Editing from the dashboard

You can also edit stack.json directly from the dashboard under Project Settings → Stack Contract. Changes trigger a new deployment automatically.

Validation

Swisblade validates your stack.json before every deploy:

  • All source.repo URLs must be accessible (with PAT if private)
  • All connects_to references must point to services defined in the same file
  • All needs values must be supported types
  • All variables listed in requires_env must exist in the project vault before deploying