Project config and Plans

The Project config is one YAML file that says what a Project runs. You change the file; Cloudgate shows a Plan for each Environment, and nothing happens until you Apply it.

Applies to: Members can read and planApplying needs permission on each Service

The Project config describes each Service by its Config name: its kind, size, source, build, port and variable names. It is kept either in Cloudgate, edited on the Project’s Config tab, or in your repository as cloudgate.yaml (or cloudgate.yml) at the root, unless you name another path.

A Plan is one Environment’s list of what applying the config would create, change and destroy. Each Environment has at most one open Plan.

What you can do

  • Describe Applications (web, web-private, worker, cron, static), PostgreSQL, MySQL, Redis, buckets and Compose stacks in one file.
  • Link variables to another Service’s Outputs, such as a database’s URL.
  • Keep the file in Cloudgate or in your repository, and move it either way.
  • Edit a Cloudgate-kept config from a folder on your computer with the CLI, and build apps from that folder’s subfolders.
  • Review each Environment’s Plan, including drift in a cloud, and Apply or dismiss it.

An example cloudgate.yaml

A shop with a web app, a background worker, a nightly report, PostgreSQL, Redis and a bucket for uploads:

# yaml-language-server: $schema=https://cloudgate.octabyte.app/backend/schema/project-config/v1.json
version: 1

services:
  web:
    kind: web
    description: The storefront
    size: small
    source:
      github: northwind-labs/storefront
      path: apps/web
    build:
      type: nixpacks
    port: 3000
    env:
      - SESSION_SECRET
      - DATABASE_URL: pg-main.url
      - REDIS_URL: cache.url
      - S3_BUCKET: uploads.name
      - S3_ENDPOINT: uploads.endpoint
      - AWS_ACCESS_KEY_ID: uploads.access_key_id
      - AWS_SECRET_ACCESS_KEY: uploads.secret_access_key
    build_args: [NEXT_PUBLIC_SITE_URL]

  jobs:
    kind: worker
    size: xsmall
    source:
      github: northwind-labs/storefront
      path: apps/jobs
    command: node
    args: [dist/worker.js]
    env:
      - DATABASE_URL: pg-main.url
      - REDIS_URL: cache.url

  nightly-report:
    kind: cron
    source:
      github: northwind-labs/storefront
      path: apps/jobs
    command: node dist/report.js
    schedule: "0 3 * * *"
    timezone: Europe/Berlin
    timeout: 30m
    env:
      - DATABASE_URL: pg-main.url

  pg-main:
    kind: postgres
    size: small
    version: "18"
    database: storefront
    user: storefront

  cache:
    kind: redis
    version: "8"

  uploads:
    kind: bucket

What the fields mean:

  • Config names (web, pg-main) are lower-case letters, digits and hyphens, starting with a letter, at most 63 characters. A Plan matches entries by Config name, so a renamed entry reads as a new Service to create and the old one to destroy.
  • env lists names only. SESSION_SECRET is set in the console. DATABASE_URL: pg-main.url is a wired variable: Cloudgate fills it from pg-main’s url Output at each Deployment and never saves it.
  • size is xsmall to 2xlarge, or { cpu: 1, memory: 2 GB }. See Applications for the table.
  • A database version is its image tag and must be quoted: "18" runs postgres:18.
  • source takes github, gitlab, gitea or bitbucket with owner/repo, a git URL (no credentials in it), an image, or a folder: a subfolder of a Project folder, such as { folder: apps/web }. A web, worker, static or cron can take a folder; a web-private cannot, and a folder is never combined with another source key.
  • build.type is nixpacks, railpack, dockerfile, heroku_buildpacks or paketo_buildpacks.
  • kind: compose names a compose file in a repository (source, file, type). The file’s contents stay in the repository.

Kinds the config cannot describe yet, such as MongoDB, MariaDB and libSQL, appear as kind: mongo with managed: console. A Plan never changes or destroys a console-managed entry.

Edit a config kept in Cloudgate

  1. Open the Config tab

    Open the Project, for example storefront, and its Config tab.

    cloudgate.octabyte.app/projects/…/config
    The text above, one plan card per Environment below.
  2. Edit and plan

    Change the text and press Save and plan. Cloudgate plans each Environment below; nothing is applied, and the text is stored only when a Plan of it is applied. Discard edits throws the change away.

  3. Review the Plan

    Each Environment’s Plan lists Creates, Changes and Destroys, plus drift, notes, held builds and major version upgrades. In a cloud, each line can show the real resources it makes, with CPU, memory and cost.

    cloudgate.octabyte.app/projects/…/config
    Review what each line does before you apply.
  4. Apply

    Press Apply. Creates run first, then changes, then destroys, each as its own step. Or press Dismiss to drop the Plan.

Native settings for Swarm, AWS and Google Cloud

An entry the config describes can carry a native block with settings Cloudgate’s own fields do not cover, written in the platform’s own spelling. Each value is laid over what Cloudgate writes for the Service, never adds a resource, and shows as its own Plan line marked native.

services:
  web:
    kind: web
    source: { folder: apps/web }
    native:
      docker:
        StopGracePeriod: 30000000000   # nanoseconds, as docker service inspect shows it
      aws:
        "aws_ecs_service.service":
          health_check_grace_period_seconds: 60
Block Where it applies What it holds
native.docker A Server Labels, HealthCheck, RestartPolicy, UpdateConfig, RollbackConfig, StopGracePeriod and Ulimits, as the Docker Engine API takes them. A cron takes Labels, StopGracePeriod and Ulimits; a bucket takes Labels
native.aws AWS hashicorp/aws arguments, keyed by the OpenTofu address the Plan’s cloud lines show, such as "aws_db_instance.database". The ECS container is "aws_ecs_task_definition.service".container_definitions, in ECS’s camelCase
native.gcp Google Cloud hashicorp/google arguments, keyed the same way, such as "google_cloud_run_v2_service.service" or "google_sql_database_instance.database"

Every Plan checks every block on every Deploy target, so a typo shows on a Server’s staging Plan rather than on the first deploy to AWS. A refusal names the full path and the reason: an address the entry’s kind does not make, an argument the pinned provider does not have, an OpenTofu meta-argument, or a locked setting such as tags, region, labels in traefik.*, com.docker.* or io.cloudgate.*, or CPU and memory (use size). An exact cloud size, such as an RDS instance class or a Cloud SQL tier, wins over size.

Edit the config from a Project folder

A config kept in Cloudgate can also be edited as a file on your computer, with the CLI. cloudgate link --whole-project makes the folder a Project folder and downloads the config into it as cloudgate.yaml: a working copy. Cloudgate keeps the config, never reads the working copy on its own, and the console still edits it. The CLI adds /cloudgate.yaml to .gitignore, so the copy is never committed.

  • cloudgate config plan sends the working copy as a Plan for each Environment, prints it and applies it on a yes. cloudgate deploy there does the same, then builds each app whose source is a folder.
  • cloudgate config pull replaces the working copy with the current config.

An entry with source: { folder: apps/web } is built from that subfolder after the whole folder is uploaded. Applying the Plan that creates such an app queues no Deployment: it waits for its first upload, since there is nothing to build before one.

What is the Config version?

Every Project config has a Config version, a counter that every Apply moves, a console Save included. Storing the text it already holds moves nothing. A working copy remembers the version it was downloaded at, and a Plan sent from it names that version. When the config has moved on since, the Plan is refused with CONFIG_VERSION_STALE, saying when and by whom it changed, and nothing is stored, so your copy never undoes a teammate’s change. Pull, make your edits again, and plan.

Keep the config in your repository

On the Config tab, Move to a repository asks for the git provider connection, the repository and the path. Each Environment reads the file from its Config branch (Environment > Settings; empty means the default branch), so staging can read develop while production reads main.

From then on, a push to the Config branch makes a Plan for that Environment, and Check for changes makes one on demand. The console shows the file read-only and never writes to your repository. Move into Cloudgate brings it back, keeping the copy from the default branch or from an Environment’s branch. A move applies nothing; it shows each Environment’s Plan first.

Drift in a cloud

Drift is a change someone made by hand in the AWS or Google Cloud console. A Plan lists it on its own. Applying always puts Cloudgate’s version back (the button reads, for example, “Apply: put AWS back”). A cloud change that finds drift stops before changing anything, and the drift becomes the open Plan. To keep a hand change, write it into the config. See Cloud accounts.

Plan states

State Meaning
open Waiting for Apply or Dismiss. One per Environment.
applied Every step ran.
partly applied Some steps ran; the results say which failed.
dismissed Someone dropped it.
superseded A newer Plan replaced it.
unchanged The config matched what runs; nothing to do.

A Plan whose commit or settings moved on since it was made is refused; make a new one.

What you cannot do

  • A push never applies by itself; a person always presses Apply.
  • An Agent can ask for a Plan but never applies or dismisses one.
  • A field Cloudgate does not know refuses the Plan.
  • The config never holds variable values, replica counts or per-Environment settings such as Domains and branches.
  • One Service you may not change refuses the whole Apply.

Questions

Does a push to my repository change what runs?

No. A push to the Config branch makes a Plan, which waits for someone to Apply it. Nothing is applied by itself.

Can I put secret values in cloudgate.yaml?

No. The config holds variable names only. Values are set in the console, encrypted at rest, and never written to the file.

Can an AI agent apply a Plan?

No. An Agent can ask for a Plan and read it, but only a person can Apply or dismiss one.

What happens to a field Cloudgate does not know?

The Plan is refused and names the field, so a typo never passes silently.

Can I edit the config from my editor?

Yes, for a config kept in Cloudgate. cloudgate link --whole-project downloads it as a working copy, and cloudgate config plan sends it back as a Plan. An edit made from an older version is refused, so it never undoes a teammate's change.

Something missing or wrong on this page? Email support@octabyte.io, or start a free trial and try it in the console.