Cosmoner Docs
Guides

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:

  1. .cosmoner/deployment.yaml
  2. .cosmoner/deployment.yml
  3. deployment.yaml
  4. deployment.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: api

Or 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: api

Example

# 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: dist

Environment 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.

FormWhat it does
value: productionA literal, committed with the file. Non-sensitive configuration only.
from_variable: NAMELinks a project variable. The stored value is read when the app is built and run.
from_secret: NAMELinks a project secret. The value stays in the vault.
secret: trueMarks 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:

  1. port, when the file or the app's settings state one.
  2. The port in your Dockerfile's EXPOSE, for docker builds.
  3. 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

FieldTypeDescription
versionnumberVersion of the file format. Optional — a file without it is read as version 1, the only version there is.
namestringOptional display name for the deployment described by the file.
regionstringRegion slug to preselect, e.g. ams. Ignored when it is not a region you can deploy to — see Sizes and regions.
environmentdefault | development | staging | productionWhich environment from_variable and from_secret resolve against. Defaults to default.
serviceslistOne or more services (max 10). Required.
$schemastringOptional, for editors that read the schema URL from the document. Ignored when the file is applied.

Service

FieldTypeDescription
namestringRequired. Lowercase letters, numbers, and hyphens (max 32 chars). Must be unique within the file.
typeservice | staticDefaults to service. static builds once and is served as files.
source_dirstringDirectory 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.strategynixpacks | dockerdocker builds the Dockerfile in source_dir; nixpacks detects the language. Defaults to auto-detection.
build.commandstringBuild command. Leave unset to auto-detect. Ignored by docker builds, which run the Dockerfile.
build.output_dirstringDirectory the build writes the site into. Static sites only.
run_commandstringCommand that starts the service. Web services only.
portnumberPort the process listens on. Optional — see Ports. Not allowed on static sites.
http_portnumberDeprecated — use port.
internal_portnumberDeprecated — use port.
instance_sizestringSize slug to preselect, e.g. shared-s. Ignored when it is not a size you can buy — see Sizes and regions.
instancesnumberInstance count (1–10).
autodeploybooleanDeploy automatically on push to the selected branch.
envslistEnvironment variables (max 100). Keys must be unique within a service.

Environment variable

FieldTypeDescription
keystringRequired. Letters, numbers, and underscores, starting with a letter or underscore.
valuestringA literal value.
from_variablestringName of a project variable to link.
from_secretstringName of a stored secret to link.
secretbooleanMarks 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:

ModeWhat the file does
Compare onlyDifferences are listed. Nothing is written. This is where an app starts.
Apply on every pushThe 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 fileIt 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: true variable is a prompt.

On this page