Skip to main content

Installation

The CLI needs Node.js 24 or later.

Usage

Commands that work on many things are grouped: overlayed bundles, overlayed jobs and overlayed releases each take a subcommand, e.g. overlayed releases create. Run a group on its own, or add --help, to list its subcommands.

Authentication

You can authenticate in two ways:
  1. Interactive login - Run overlayed login to authenticate via browser
  2. Environment variable - Set OVERLAYED_API_KEY for CI/CD or programmatic use
The environment variable takes precedence over stored credentials when both are present.

Multiple Accounts

Each overlayed login adds an account instead of replacing the previous one, so you can stay logged in to several applications at once, including ones owned by different emails. Run overlayed accounts to see them. Commands pick the account by application: the one whose API key is scoped to the applicationId in the nearest overlayed.config.ts, or to OVERLAYED_APPLICATION_ID if that is set. When that is not the account you last logged in to:
  • In a terminal, the CLI asks before switching to it, and remembers the switch as the new default.
  • Without a terminal (CI, scripts, coding agents), the CLI uses it for that run and leaves the default alone. Runs in different applications can therefore happen in parallel without affecting each other.

Choosing the Application

overlayed bundle uploads to the applicationId in your overlayed.config.ts. Every other command works on the first of these that is set:
  1. OVERLAYED_APPLICATION_ID
  2. The applicationId in the nearest overlayed.config.ts
  3. The application the API key is scoped to, when it is scoped to exactly one
So a CI job that only releases needs no config file: OVERLAYED_API_KEY and OVERLAYED_APPLICATION_ID are enough. If the application named by (1) or (2) isn’t one the API key can reach, the command fails and says so, rather than sending requests that would be refused. A key scoped to several applications needs OVERLAYED_APPLICATION_ID (or a config file) to pick one.

Running in CI

The CLI behaves the same in a terminal and in CI, with these differences when there is no terminal to ask in (CI runs, scripts, coding agents):
  • Nothing prompts. A command that would ask for something fails instead, naming the flag or environment variable that answers it: overlayed bundle needs --app/--site and a bundle name, and overlayed login asks you to set OVERLAYED_API_KEY.
  • Public channels don’t ask for confirmation. In a terminal, releasing, promoting, publishing, raising a rollout or cancelling on a public channel asks first. --yes skips the question; without a terminal the command goes ahead, since whoever wrote the pipeline has already decided. Private channels never ask.

Exit Codes

--help, --version and a command group run without a subcommand exit 0.

Waiting

overlayed bundle, releases create, releases promote, jobs wait and releases wait wait for the build to finish and fail if it doesn’t succeed. They give up after 15 minutes. Change that with --wait-timeout <seconds> or the OVERLAYED_WAIT_TIMEOUT environment variable (the flag wins). A wait that times out exits 1, and the build carries on on the server: wait on it again with overlayed jobs wait or overlayed releases wait.

JSON Output

Add the global --json flag to any command to print only its result, as one JSON document on stdout. Progress, warnings and prompts go to stderr. The result includes ids, statuses and dashboard links, so a later step can pick them up:
Each result is keyed by what it describes: outcome is how a wait ended (succeeded, failed, cancelled, revoked or timed_out, or null when nothing was waited on), and error says why the command fails, or is null. A release has its id, version, status, draft flag, channel, bundle, rollout, minimum app version and dashboard link; releases list, show, latest and wait add commit_hash, has_modern_installer and created_at. A failed job carries its latest run’s message as build_error. A command that fails prints { "error": { "message": … } }, with status, kind, required_permissions, issues or missing_urls when the API gave them. A command that fails after doing some of its work (a build that failed, a release that didn’t build) prints its usual result instead, so the ids it produced aren’t lost, with the failure in it: error for the release commands, each bundle’s error for bundle, and release_error for bundle --release. Either way it exits 1; check the exit code rather than a field. When releases promote or bundle --release stopped because the API returned an error creating a release, error_kind (release_error_kind for bundle --release) is that error’s kind, the same as kind above; otherwise it’s null. A release to a public channel is refused while the application has no privacy policy URL or terms of service URL, drafts included. The release commands then say which is missing and where to add it (Settings › Application in the dashboard), and --json gives kind public_release_missing_legal_urls with missing_urls: privacy_url, terms_url or both. releases promote puts missing_urls beside error_kind, and bundle --release puts release_missing_urls beside release_error_kind.

Update Checks

Every command checks npm for a newer @overlayed/cli, and overlayed bundle also checks the @overlayed/app and @overlayed/electron versions installed in your project. If any are out of date, a warning is printed to stderr before the command runs. The check never fails a command: if the registry can’t be reached or doesn’t answer within 1.5 seconds, it is skipped silently. Snapshot installs (e.g. @canary) are not checked, and neither are --help and --version, which print without touching the network.

Config File Lookup

Commands that need your overlayed.config.ts look for it (.ts, .mts or .js) in this order:
  1. The current directory, then each parent directory. The nearest one is used.
  2. If none is found, up to 3 directories below the current directory (so running from a monorepo root finds packages/app/overlayed.config.ts). node_modules and .git are skipped.

Commands

overlayed login

Authenticate with the Overlayed platform. This is required for local development. Opens the dashboard’s API key creation page with the key name prefilled as cli and these permissions preselected, so the resulting key can bundle and release without further setup: The permissions are only a starting point — add or remove any of them before creating the key. Your role must hold a permission for the key to have it: Developers can’t create or update releases, so they untick those two and get a key that bundles and reads but doesn’t release. Without a terminal overlayed login fails: set OVERLAYED_API_KEY instead (see Running in CI).

overlayed logout

Log out of the account that commands in the current directory use. Only that one stored account is removed; other accounts stay logged in, including others with the same email. No request is made, so an expired or revoked key can still be removed. Options: --email and --application can be combined to match accounts that have both.

overlayed accounts

List the accounts you are logged in to, with the application each API key is scoped to and the last four characters of the key.
* marks the account that commands run from the current directory use. (default) marks the account you last logged in or switched to, which is used when no application can be determined. See Multiple Accounts.

overlayed whoami

Display information about the currently authenticated user.

overlayed init

Initialize your local development environment. This command:
  • Fetches your application metadata from the Overlayed API
  • Creates a .overlayed/meta.json file with cached application data
  • Must be run after overlayed login and from your project (see how the config file is found)
This only needs to be run once per project.

overlayed bundle

Bundles the app and site for deployment. This command looks for an overlayed.config.ts file (see how the config file is found), uploads a bundle of each, and waits for them to be processed. With --release it then releases them to a channel. Options: With no --app or --site, a terminal asks which to bundle. Without a terminal (or with --json), pass --app and/or --site, each with a name unless --no-wait is set. Each uploaded bundle prints its bundle id and build job id, with links to them in the dashboard. A build that fails, is cancelled or is still running when the wait times out makes the command exit 1. Examples:

Bundle and release

--release <channel> releases what was just bundled, once its build succeeds:
It also takes the release options (--draft, --rollout, --rollout-start, --rollout-end, --public-notes, --internal-notes, --min-app-version, --yes), which apply only with --release.
  • The channel and versions are worked out, and a public channel is confirmed, before anything is uploaded.
  • With both --app and --site, the app is released first and waited on, then the site, with its minimum app version set to the new app version. --min-app-version is for a site bundled on its own.
  • If a build fails, nothing is released and the command exits 1.
  • If the app release goes out but the site’s doesn’t, the command exits 1 and names the app release. If the site’s release was refused, failed or was cancelled, it also prints the overlayed releases create command that releases the site on its own. If the wait gave up while the site was still building, follow it with overlayed releases wait.
  • --release needs --app/--site given explicitly, waits for the builds (so not with --no-wait), and can’t be used with --debug or --debug-files.
  • A channel with auto-release on bundle turned on is refused before uploading: the platform already releases every bundle built to it, so --release would release it twice. Leave that channel to auto-release, or turn the setting off.
With --json the result has bundles, each with its own error, plus releases and release_error (why the releases stopped, or null; a failed build releases nothing and leaves it null, with the build’s error set instead), and release_error_kind (the API error’s kind, see JSON output).

overlayed bundles

overlayed jobs

Every uploaded bundle is processed by a build job.

overlayed releases

A release puts a bundle on a channel. Releasing an app builds its installer; releasing a site deploys it. Each release builds on the server after it’s created.

overlayed releases create

Release a bundle to a channel.
Plus the release options. It prints the release’s id, version, channel, status, rollout and a link to it in the dashboard (with --json: { "release": …, "outcome": …, "error": … }), and exits 1 unless the release built (or, with --no-wait, was created).

overlayed releases promote

Release a release’s bundle on another channel, e.g. from beta to stable, so what was tested is exactly what ships. Like the dashboard’s Promote, it creates a new release of the same bundle on the target channel, which builds there.
Plus the release options. The new release keeps the source’s public and internal notes unless --public-notes/--internal-notes give new ones, and a site promoted on its own keeps its minimum app version. With --type both the app is promoted first and waited on, then the site, with its minimum app version set to the promoted app’s version. If the app doesn’t build, the site isn’t promoted. With --no-wait both are created at once, as the dashboard does. With --json the result is { "releases": [ … ], "error": …, "error_kind": … }.

overlayed releases publish

Publish a draft, taking it live. If the draft was created without a rollout and its channel has a default rollout duration, the rollout window opens now, at publish (see Rollout). An application that requires draft review for public channels doesn’t let the CLI publish there; the command says so.

overlayed releases rollout

Set the percentage of users a release rolls out to, from 0 to 100. Once a release is published its rollout can only go up, and a published release that has no percentage (it reaches everyone, or rolls out over a window) can’t be given one.

overlayed releases cancel

Cancel a release that hasn’t finished building, or revoke a built one. After a revoke, its users fall back to the previous eligible release on the channel. A release that is already cancelled, failed or revoked can’t be cancelled again, and none of those can be changed with publish or rollout either.

overlayed releases list, latest, show, wait

overlayed releases download

Download a built app release’s installer: classic (the default), or modern for the branded installer when the release has one. It is saved under the installer’s own file name in the current directory, or at --output. --url prints a download link instead, which expires after 5 minutes, plus any headers it needs.

Release Versions

Every release needs a version, given in one of two ways:
  • A version, like 1.4.0 or 2.0.0-beta.1: SemVer, with no leading zeros.
  • A bump: patch, minor or major bumps the channel’s latest release of the same bundle type (drafts included; cancelled and failed releases don’t count). A channel with no release of that type bumps from 0.0.0, so patch gives 0.0.1.
The version must be higher than the channel’s latest release of that type and not already used there; the API refuses anything else, and the command says which rule it hit.

Release Options

releases create, releases promote and bundle --release take these:

Rollout

  • --rollout <percent> sends the release to that share of users. It can’t be combined with a window.
  • --rollout-start and --rollout-end make a window: 0% of users at the start, rising evenly to 100% at the end. --rollout-start alone releases to everyone at that time. --rollout-end alone starts the window when the release is created.
  • With no rollout option, a release uses its channel’s default rollout duration, if the channel has one, as a window starting when it’s created; otherwise it goes to everyone at once. A draft gets no window until it’s published: overlayed releases publish then opens the channel’s default window from that moment, as the platform’s automatic releases do.

Migrating to 2.0

CLI 2.0 changes what CI pipelines see:
  • overlayed bundle exits 1 when a build fails, is cancelled or times out. It used to exit 0 in all three cases.
  • Waiting gives up after 15 minutes by default instead of about 5 (see Waiting).
  • Without a terminal, commands fail instead of prompting (see Running in CI).
See the changelog for everything else in the release. Read more about deploying your overlay here, and about shipping from CI in Shipping from GitHub Actions.