Skip to main content
This guide walks through setting up an app branch on an existing app template: writing the branch config, choosing how to structure branches and install groups, syncing settings into Nuon, triggering runs, and approving them.

Prerequisites

  • An app template already in Nuon, with at least one install.
  • The Nuon CLI installed and authenticated (nuon auth login).
  • For pull request previews, the Nuon GitHub App connected in your org for the repository’s owner. See connecting a repository.

Write a branch config

Add a branch.toml at the root of your app config directory (next to metadata.toml), or put one file per branch under branches/ (for example branches/main.toml). You cannot use both layouts in the same app directory.
branches/main.toml

Key fields

  • The repo block. Use [connected_repo] for a repository connected through the Nuon GitHub App, or [public_repo] for a public one. Exactly one of the two. repo is typically owner/name (for example acmeco/my-app-config). directory is the path to your app config within the repo, or "." at the root.
  • name is the branch’s name in Nuon (from this key, not the filename). Pass it to nuon branches trigger and related commands.
  • Install group order and default. Lower order deploys first. When you declare any install_groups, exactly one install group must set default = true (usually your catch-all / production wave). Sync fails if none or more than one is default.
  • [preview] (optional but recommended). Defaults for preview runs only (pull request or manual CLI/dashboard). Use them to test a change before it merges into the tracked branch. Not used by fleet runs. See Previews.
Full field list: branch config reference.

Control when the branch runs

Omit [run] (or set mode = "push") to run on every qualifying push to the tracked branch. Other modes:
on_tag starts a run when a tag matching tag_prefix lands on that branch’s history.
on_github_label starts a run when a merged pull request carries that exact label. It requires [connected_repo]. Use manual_only when nothing automatic should start a fleet run. Manual triggers (nuon branches trigger, dashboard) remain available in every mode. Full trigger table: What triggers an app branch run.

One branch file or several

Use either a root branch.toml or branches/*.toml, not both. The name key inside each file is the Nuon app branch name, not the filename. Use branches/ when the app has more than one app branch (for example one per snowflake customer, or cadence cohorts). Which pattern to pick is under Structure branches and install groups and in concepts.

Structure branches and install groups

Pick a layout that matches how your customers take updates. Labels on install configs are what install groups select; branch files only declare the selectors. Install group names are yours (for example stage, production, uat, canary, preview); sketches below use stage then production.

Snowflake customers

Use one app branch per customer to give each its own approvals and cadence. Install groups on that branch define environment waves:
branches/acme.toml
Each customer’s installs carry customer + env labels in their install TOMLs.

Homogeneous fleet

One app branch, many installs that share the same app config (for example single-tenant customers in the vendor’s cloud). Install groups are environment waves across the fleet:

Cadence cohorts

Two (or more) branches of the same app and repo: fast customers on every push, slower customers on a gated mode.
  • branches/main.toml: [run] mode = "push", with install groups for installs labeled cadence = "continuous".
  • branches/monthly.toml: [run] mode = "on_tag" (or on_github_label / manual_only), install groups for cadence = "monthly".
Remember: two branches of one app cannot share an identical label_selector, and an install can sit on only one branch.

Sync the branch config

Use nuon branches sync to reconcile branch settings into Nuon. Do not use nuon apps sync for branch settings:
This creates or updates the branch in Nuon: install groups, and any [run] / [preview] you set. The first sync for a branch (with a connected or public repo) also starts an app branch run that fetches the tracked ref, syncs the app config, and builds OCI artifacts for components and the sandbox (when configured). With no installs on the branch yet, that run stops after the build. Later syncs update branch settings; shipping config to installs is a branch run from a push, tag, label, or nuon branches trigger. Confirm:

Label your installs

Pin each install to a branch with app_branch, and set the labels install groups select. Prefer install config files:
installs/customer-acme.toml
Changing app_branch moves the install and applies the branch’s latest non-preview run. Omitting it leaves the install’s current branch unchanged. Apply them:
Or set labels imperatively:
All labels passed to --labels must match (same AND semantics as an install group’s label_selector).

Trigger a run

Once the branch exists, a qualifying Commit pushed to the tracked branch starts a run that fetches that commit’s app config, runs building components and sandbox, then plans and deploys each install group:
You can also start a run without waiting for a push:
By default the trigger uses the tracked branch’s latest commit. With --run-type (pr, tag, or commit) and a matching --run-ref, it deploys that source instead. To test a committed ref without starting a fleet run, use nuon branches preview as described in Previews. The CLI does not send uncommitted local files to an app branch run. Watch runs with nuon branches runs --branch-id main (workflow TUI) or in the dashboard Branches view. See the TUI reference.

Approve or skip an install group

A run pauses at each install group’s plan step until someone acts on it. In the dashboard, open the app’s Branches view, then the run, and you will see the Deployment plan with each install group’s steps. For each install group:
  • Approve install group plan: read the per-install diff, then approve to let the install group’s deploy step run.
  • Skip install group: move the rollout past this install group’s deploy without applying it.
The run stops at the next install group’s plan step, so each install group is approved or skipped on its own. By default the plan waits for approval. Set auto_approve_on_policies_passing = true on an install group to approve automatically when policy checks pass. You can also subscribe to webhook events and approve through the API.

Previews

Previews are optional but recommended for testing a change before it merges into the tracked branch. A branch can roll out from push, tag, label, or manual trigger with no [preview] block. [preview] sets defaults for preview runs only. A preview never rolls install groups. It shares the early steps of a fleet run (fetch, sync config, build), then plans or applies against a single preview target install only: build-only stops after build, plan-only after plan, and apply continues to the preview install. Fleet runs (push, tag, label, nuon branches trigger) are separate and do not run [preview]. A preview run starts in one of two ways: For most preview modes you need a [preview] block that sets depth and (when required) the target install. See connecting a repository for the GitHub App.

Modes

[preview] fields

Use one of label_selector, install_name, or install_id. For plan-only and apply, a target is required. build-only and mode = "none" do not take a target install.
Create a dedicated preview install and sync it before you rely on apply.

Start a preview

Manual (CLI or dashboard), with an optional --mode:
Pull request: open or update a PR into the tracked branch (starts automatically from [preview]), or preview by number:
After you connect the GitHub App once for an owner, every branch tracking a repo under that owner can post PR feedback. A [public_repo] branch is fine if the owner is connected.

Multiple apps in one repository

In a repository with several app configs (for example example-app-configs), set ignore_changes_regex so this branch only runs when something under its tree changed. The value is an RE2 pattern matched against every changed file path; if the entire changed set matches, the run is not attempted.
send_statuses_on_ignore posts a successful commit status when a run is skipped so a required check does not block the PR.

Roll back a change

Every config change to an install is recorded as an app config version, and any earlier version can be applied again, to one install or to a whole install group, with a plan in front of it. The rollback guide walks through the exact calls.

Command reference

nuon apps branches is a deprecated alias of nuon branches.

Troubleshooting

Sync failed: one install group must be default. When install_groups is non-empty, set default = true on exactly one install group. Sync failed: more than one default. Only one install group may be default. The branch synced but has no install groups. The branch config is missing its [connected_repo] / [public_repo] block, or install groups were omitted. Add them and nuon branches sync again. A push did not start a run. Check [run].mode, that branch matches the ref you pushed, and ignore_changes_regex (a change outside this app’s tree in a shared repo is skipped on purpose). The pull request has no Nuon comment. Your org has no GitHub App connection for that repository’s owner, or [preview].comment is false. The preview run itself can still succeed. Preview sync failed needing an install target. For plan-only or apply, set preview.label_selector, install_name, or install_id, and sync that install first. An install group deployed to nothing. No install carried the selector’s labels. Check with nuon installs list --labels ....

Next steps

How app branches work

Triggers, structure patterns, and install version history.

Walkthrough

Roll a change through the eks-simple example app end to end.

Roll back an install

Re-apply a previous config version to an install or a whole install group.

Branch config reference

Every field in a branch file.

Webhooks

React to branch runs from your own systems.