openship.json
The declarative deploy config for Openship — like vercel.json or railway.toml. Declare framework, build, runtime, env, domains, routes, resources, services and monorepo layout, and Openship deploys the same way every time.
openship.json is a repo-root file that tells Openship how to build, run, route, and scale a
project. It mirrors what you'd otherwise set in the deploy wizard,
so a repo becomes "ready to ship on Openship" and auto-deploy on push
and openship deploy become deterministic — no wizard needed.
Authoritative overlay
Openship auto-detects your stack first, then applies every field present in openship.json
on top. Fields you omit keep their detected value. So a good openship.json is small —
declare only what you want to override or pin, not the whole detected config.
Add the $schema line for editor autocomplete and inline validation:
{
"$schema": "https://openship.io/openship.schema.json",
"framework": "nextjs",
"port": 3000
}Validate it any time with the CLI:
openship config init # scaffold a starter openship.json
openship config validate # check it against the schemaIt's JSON, not JSONC — no comments, no trailing commas.
Build
Prop
Type
Runtime
Prop
Type
Environment variables
env is an object. A value is a plain string, or { "value", "secret" } to mark a secret
(encrypted at rest — never returned to the client afterward).
{
"env": {
"NEXT_PUBLIC_URL": "https://app.acme.com",
"DATABASE_URL": { "value": "postgres://…", "secret": true }
}
}Domains
domains is an array of hostnames or objects. A bare label ("myapp") is a free
*.opsh.io-style subdomain; a dotted hostname ("app.acme.com") is a custom domain.
{ "domains": ["app.acme.com", { "domain": "api.acme.com", "port": 8080, "type": "custom" }] }Prop
Type
Routes
routes reproduces vercel.json-style routing, compiled to the reverse proxy at deploy.
Prop
Type
Resources
Cloud sizing — a named tier, or explicit values (which become the custom tier). Ignored on
self-hosted instances. See Sleep mode & resources.
Prop
Type
Services (compose)
Declaring services makes the project a multi-service (Docker) project — see
Compose / multi-service. Each entry requires a name.
{
"services": [
{ "name": "web", "build": ".", "ports": ["3000"], "exposed": true, "domain": "app.acme.com" },
{ "name": "db", "image": "postgres:17", "volumes": ["pgdata:/var/lib/postgresql/data"],
"env": { "POSTGRES_PASSWORD": { "value": "…", "secret": true } }, "restart": "unless-stopped" }
]
}Prop
Type
Monorepo
monorepo overrides Openship's detected sub-apps. Entries in apps[] are matched to detected
sub-apps by rootDirectory and override their build settings — they don't declare apps from
scratch (the detector finds the apps).
{
"monorepo": {
"workspace": { "packageManager": "pnpm", "prepareCommand": "pnpm install && pnpm codegen" },
"apps": [
{ "name": "web", "rootDirectory": "apps/web", "framework": "nextjs", "port": 3000 },
{ "name": "api", "rootDirectory": "apps/api", "framework": "hono", "port": 8080 }
]
}
}Prop
Type
Not supported yet
sleepMode, monorepo sharedPaths, and per-app domain/env/exposed are accepted by the
validator but not applied — leave them out. Set sleep mode and per-app domains in the
dashboard for now.
How it maps
openship.json | Deploy wizard / API |
|---|---|
framework, packageManager, *Command, outputDirectory, buildImage, productionPaths, rootDirectory | Build settings |
port, productionMode, runtime | Runtime settings (hasServer, runtime isolation) |
env | Environment variables (seeded as editable rows) |
domains | Public endpoints / custom domains |
routes | Reverse-proxy routing (routingConfig) |
resources | Cloud resource tier / custom sizing |
services | Compose services |
monorepo | Monorepo sub-apps + workspace |