App Configuration Files
Commit a .cosmoner/deployment.yaml to your repository to describe your app's build, runtime, and environment configuration — the deploy wizard fills its form in from it, and your editor validates it as you write.
Overview
When you deploy an app from a git repository, you normally configure the source directory, build settings, ports, and environment variables by hand in the deploy wizard. A configuration file moves that into your repository: commit a .cosmoner/deployment.yaml, and the wizard reads it as soon as you select the repository and offers to fill the form in from it.
Nothing is applied until you ask for it. When the file is found, the wizard shows Fill in from file — press it and every setting the file defines is filled in, and every setting stays editable afterwards. Deploying by hand from a repository that has a file is always still an option.
A file can describe one or more services. Each deploy sets up one service — when a file defines several, you pick which one to fill the form from, and run the wizard again for the others.
Configuration files apply to apps deployed from a git repository. Apps deployed from a container image are configured in the wizard.
File location
The file is looked up on the branch you selected, in this order:
.cosmoner/deployment.yaml.cosmoner/deployment.ymldeployment.yamldeployment.yml
.cosmoner/deployment.yaml is the recommended location. If you'd rather not add a directory, put a deployment.yaml (or deployment.yml) at the root of the repository instead. The first file found is used, so a file in .cosmoner/ takes precedence over one at the root.
Paths in the file
Paths are relative to the repository root, wherever the file itself lives. source_dir: . (or leaving source_dir out) means the root of the repository, even when the file is in .cosmoner/. For a monorepo, point source_dir at the service's directory, e.g. apps/api.
The build runs from source_dir. That directory is what gets built, and for docker builds the Dockerfile is read from there.
Editor support
The format is published as a JSON Schema at https://cosmoner.com/schemas/app.schema.json. Point your editor at it and you get completion for every field, a description on hover, and an error on a mistyped key — before you push.
In VS Code, Zed, Neovim, and anything else running the YAML language server, add a comment to the top of the file:
# yaml-language-server: $schema=https://cosmoner.com/schemas/app.schema.json
services:
- name: apiOr set it once for every app file, in VS Code's settings.json:
{
"yaml.schemas": {
"https://cosmoner.com/schemas/app.schema.json": [".cosmoner/deployment.yaml", ".cosmoner/deployment.yml"]
}
}JetBrains IDEs read the same URL from a $schema key in the document itself:
$schema: https://cosmoner.com/schemas/app.schema.json
services:
- name: apiExample
# yaml-language-server: $schema=https://cosmoner.com/schemas/app.schema.json
version: 1
name: my-platform
region: ams
environment: production
services:
- name: api
type: service
source_dir: apps/api
build:
strategy: docker
command: bun run build
run_command: bun start
port: 3000 # optional — see Ports
instance_size: shared-s
instances: 2
autodeploy: true
envs:
- key: NODE_ENV
value: production
- key: API_URL
from_variable: PUBLIC_API_URL # a project variable
- key: DATABASE_URL
from_secret: DATABASE_URL # a stored secret, resolved by name
- key: STRIPE_KEY
secret: true # you are asked for the value in the wizard
- name: web
type: static
source_dir: apps/web
build:
command: bun run build
output_dir: distEnvironment variables, secrets, and variables
A variable takes its value from exactly one of four places. Setting two is an error, so the file always says plainly where a value comes from.
| Form | What it does |
|---|---|
value: production | A literal, committed with the file. Non-sensitive configuration only. |
from_variable: NAME | Links a project variable. The stored value is read when the app is built and run. |
from_secret: NAME | Links a project secret. The value stays in the vault. |
secret: true | Marks the variable sensitive without giving it a value — the wizard asks for it and stores it masked. |
Never commit a secret value. A file that sets both value and secret: true is rejected, and nothing from it is applied: the value is in your git history, and the fix is to rotate it, not to deploy it.
How a reference is resolved
from_secret and from_variable name an entry in your project, and the name is resolved against your project when the wizard reads the file — the file itself never carries a value, and a linked secret's value is not shown in the wizard, returned by the API, or written into your app's configuration. It is read from the vault when the app deploys, and the link keeps working after you rotate the secret.
The top-level environment field says which environment the names resolve against, defaulting to default. An entry in that environment wins over one of the same name in default.
If a name has no matching entry, the wizard says so and fills the row in empty — create the secret or variable and fill the form in again, or type the value by hand.
Ports
Most services need no port setting. Your app is given its port in the PORT environment variable, so a service that listens on $PORT is reachable without anything in the file.
When your service listens on a fixed port instead, the port is chosen in this order:
port, when the file or the app's settings state one.- The port in your Dockerfile's
EXPOSE, fordockerbuilds. 8080.
PORT is always set to the chosen port, unless you set PORT yourself in envs — in that case, set port to the same value. Static sites are served by the platform and take no port.
http_port and internal_port from earlier versions of this format are still read, as port, but are deprecated. A file that sets port alongside either is rejected.
Reference
Top level
| Field | Type | Description |
|---|---|---|
version | number | Version of the file format. Optional — a file without it is read as version 1, the only version there is. |
name | string | Optional display name for the deployment described by the file. |
region | string | Region slug to preselect, e.g. ams. Ignored when it is not a region you can deploy to — see Sizes and regions. |
environment | default | development | staging | production | Which environment from_variable and from_secret resolve against. Defaults to default. |
services | list | One or more services (max 10). Required. |
$schema | string | Optional, for editors that read the schema URL from the document. Ignored when the file is applied. |
Service
| Field | Type | Description |
|---|---|---|
name | string | Required. Lowercase letters, numbers, and hyphens (max 32 chars). Must be unique within the file. |
type | service | static | Defaults to service. static builds once and is served as files. |
source_dir | string | Directory the service is built from, relative to the repository root — . is the root, even when the file is in .cosmoner/. Defaults to the root. See Paths in the file. |
build.strategy | nixpacks | docker | docker builds the Dockerfile in source_dir; nixpacks detects the language. Defaults to auto-detection. |
build.command | string | Build command. Leave unset to auto-detect. Ignored by docker builds, which run the Dockerfile. |
build.output_dir | string | Directory the build writes the site into. Static sites only. |
run_command | string | Command that starts the service. Web services only. |
port | number | Port the process listens on. Optional — see Ports. Not allowed on static sites. |
http_port | number | Deprecated — use port. |
internal_port | number | Deprecated — use port. |
instance_size | string | Size slug to preselect, e.g. shared-s. Ignored when it is not a size you can buy — see Sizes and regions. |
instances | number | Instance count (1–10). |
autodeploy | boolean | Deploy automatically on push to the selected branch. |
envs | list | Environment variables (max 100). Keys must be unique within a service. |
Environment variable
| Field | Type | Description |
|---|---|---|
key | string | Required. Letters, numbers, and underscores, starting with a letter or underscore. |
value | string | A literal value. |
from_variable | string | Name of a project variable to link. |
from_secret | string | Name of a stored secret to link. |
secret | boolean | Marks the variable sensitive; the wizard asks for the value. |
Sizes and regions
instance_size and region are the only two settings the file preselects on a later step of the wizard rather than filling into the form in front of you, and both take a slug rather than the name shown on the size and region pickers. A slug you cannot deploy to is ignored, silently — a file is not a way to buy a size that is not on sale.
If you are not sure of the slug, leave the field out: the wizard picks its default and you choose on the configure step. An existing app's slug is the size field on the app object returned by the Apps API.
Versioning
version states which revision of this format the file is written for. Leave it out and the file is read as version 1; state a version this platform does not read and the file is refused outright, with an error saying so, rather than being half-understood by an older reader.
It only moves when a change would make an older reader wrong about a file. Adding a new optional field is not that — an older reader ignores what it does not recognise — so a file can use new fields without changing its version.
Validation
If the file exists but is invalid — malformed YAML, a missing required field, duplicate service names, a variable that names two sources — the wizard shows the validation error and offers no fill. Nothing is applied from an invalid file, so a typo can never half-configure an app.
The wizard validates exactly what your editor does, from the same schema, with one difference: a key the platform does not recognise is an error in your editor (it is almost always a typo) and is ignored when the file is applied, so a file written for a newer field still fills in everything else.
After the app exists
An app created from a file keeps watching it. Its Configuration file section, on the app's settings page, compares the two and lists any setting where they disagree — saying for each one whether the repository changed it or you did, since the file was last applied.
By default it reports and nothing more — reconciling the two is your call. Apply the file writes every setting it states onto the app in one go, and the section's mode control decides what happens without you:
| Mode | What the file does |
|---|---|
| Compare only | Differences are listed. Nothing is written. This is where an app starts. |
| Apply on every push | The file is also written to the app on every push to the deployed branch, before the build. Settings you change in the panel are overwritten on the next push — the file is the source of truth in this mode, which is the point of it. It needs Auto-deploy on push turned on: the file is applied when a push is seen, and pushes are only seen for an app that deploys on push. Turning auto-deploy off later stops the file from being applied until it is back on. |
| Ignore the file | It is not read at all. |
Two settings are never written from a file, in any mode: instance_size and instances move your app between plans and charge your payment method, so a commit landing never resizes an app. The file asking for a different size shows up as skipped, and you change it on the app's plan page where the price is shown.
Applying pushes the settings to the app without rebuilding it: an environment variable or a port takes effect on the next deploy, and a build command applies to the next build. A push applies and builds in that order, so a commit that changes both its code and its build command gets both.
A file that references a secret or variable your project does not have is never applied — create the entry first. Applying it would deploy the app without that value, and the failure would surface later as a crash with nothing pointing at the cause.
The section also speaks up when the repository stops describing the app at all — the file deleted, no longer valid, or no longer defining the service the app was created from. In each case the app carries on with the settings it has.
What a file does not do
- It fills the deploy wizard in, is compared against the app afterwards, and reconfigures it only when you apply it or set the app to apply on push.
- It never sets a value you have not stored with us. A linked secret is a link; a
secret: truevariable is a prompt.