main and releases them to a private beta channel, and one you run by hand to promote what’s on beta
to stable.
How It Fits Together
overlayed bundleuploads your app and site as bundles, and the platform builds each one. With--release, it then releases them to a channel once they’re built.- A release puts a bundle on a channel, and builds there: an app release builds your installer, a site release deploys your site. When the app and site are released together, the app goes first and the site’s minimum app version is set to the new app version, so users never get a site that needs an app they don’t have yet.
- Promoting releases the same bundle on another channel.
stablegets exactly the bundle your testers ran onbeta, built again for that channel. - Every command fails the job when something fails. A build or release that fails, is cancelled or times out exits
1, so a broken release stops the workflow instead of passing silently.
Set It Up
Create a private beta channel
stable channel. Create a private channel named beta on the
channels page. Your backend decides who may update from it: see
Private Channels.Leave auto-release on bundle off for beta: the workflow releases to it explicitly, and
overlayed bundle --release refuses a channel that already releases every bundle by itself. Check stable too:
with auto-release on there, every bundle this workflow uploads would also go straight to stable, skipping
beta.Create an API key
Store it in GitHub
- A secret named
OVERLAYED_API_KEY, holding the key. - A variable named
OVERLAYED_APPLICATION_ID, holding your application’s id (theapplicationIdin youroverlayed.config.ts). It isn’t secret.
overlayed:
npm ci and your build run code from your dependencies, which has no business seeing a key that can release.Release pushes to beta
beta, bumping the
patch version of the latest beta release each time. Runs take turns: while one releases, the newest push waits.
GitHub keeps only the newest waiting run, which is all beta needs, since it releases a main that includes the
pushes before it.The checkout keeps no Git credentials (persist-credentials: false) and the job’s GITHUB_TOKEN can only read:
npm ci and your build run your dependencies’ code, and nothing here pushes.npm cicomes before bundling: the CLI reads the installed@overlayed/appand@overlayed/electronversions fromnode_modules, andnpm run buildproduces the files youroverlayed.config.tsincludes.- Without a terminal the CLI doesn’t prompt, so each bundle is named on the command line. The run number and attempt keep the names unique, including when you re-run a failed job.
- The step waits for the builds and both releases, up to 15 minutes each, and fails if any of them fails.
Promote beta to stable on demand
beta looks good. It promotes beta’s newest
published app and site to stable, app first.beta is releasing waits until that
release finishes rather than promoting halfway through it. Waiting isn’t the same as succeeding: if a beta run
released its app but not its site, beta’s newest site is still the previous one, so finish the site on beta
before promoting. GitHub keeps one waiting run per group: if a push
to main arrives while your promotion waits, it takes the promotion’s place, and you start the promotion again.Promoting needs no checkout and no overlayed.config.ts: OVERLAYED_APPLICATION_ID tells the CLI which
application to work on. The version input goes through env: rather than straight into the script, so nothing
typed into the form can run as a command.stable is public. In a terminal the CLI would ask before releasing there; in a workflow it goes ahead.Require an approval for stable (optional)
environment: stable on its own only names a GitHub environment; GitHub creates it unprotected, and the job starts
at once. To make every promotion wait for a person, open Settings → Environments, select (or create) stable,
and add Required reviewers. The promote job then waits until one of them approves it.The approval gates this workflow, not the key: a key with release permissions can release to any channel of its
application, including from the beta workflow. Keep the key to these workflows, and review changes to them as you
would a release.Choosing Versions
Every release needs a version, and it must be higher than the channel’s latest release of the same type.- Bump each time
- From a git tag
- Separate app and site versions
--release-version patch (or minor, major) bumps the channel’s latest release of each type, so the app and
site each count up on their own. Nothing to keep in sync, which suits a channel that gets every merge.Rolling Out Gradually
By default a release uses its channel’s default rollout duration if the channel has one (set it on the channel), rising from 0% to 100% of users over that time. A channel without one releases to everyone at once. To choose per release, add a release option:Using the Results
Add the global--json flag and a command prints only its result on stdout, with every id, status and dashboard link.
This writes the promoted releases to the run’s summary page:
FAQ
The job fails with 'No terminal to prompt in'
The job fails with 'No terminal to prompt in'
overlayed bundle, name each bundle (--app <name>,
--site <name>) and say which to bundle; for overlayed login, don’t run it in CI at all: OVERLAYED_API_KEY
replaces it.The release is refused: 'isn't higher than the latest release'
The release is refused: 'isn't higher than the latest release'
patch) or a higher
version. The concurrency block in the workflows above keeps two runs from racing for the same version.The release is refused because the channel is public
The release is refused because the channel is public
--draft; the release then waits as a draft instead of going
live.'Your API key is missing a permission'
'Your API key is missing a permission'
OVERLAYED_API_KEY secret. API keys also expire: when a working workflow starts failing to authenticate, check the
key’s expiry in the dashboard.The app was released but the site wasn't
The app was released but the site wasn't
overlayed releases create command that releases the site on its own, with the
right minimum app version: fix the cause it reports, then run that command. If the wait gave up while the site was
still building, the site release exists and holds its version: follow it with overlayed releases wait <id>,
using the site release’s id printed above the error, instead.How do I pull a bad release?
How do I pull a bad release?
overlayed releases cancel <release-id> cancels a release that is still building, or revokes one that is live.
After a revoke, users fall back to the previous release on the channel.Can I release only the site?
Can I release only the site?
--site alone. If the new site needs a newer app, add --min-app-version so users on older apps
keep the old site. See Safe Site Releases.My project is in a monorepo
My project is in a monorepo
overlayed.config.ts in the current directory or a parent, or up to three directories below it. Run
the steps from your app’s package (working-directory:) if it’s deeper than that. See
Config File Lookup. If the lockfile isn’t at the repository root, also point
actions/setup-node at it with cache-dependency-path (e.g. apps/overlay/package-lock.json), or its npm cache
step fails.The step gives up while a build is still running
The step gives up while a build is still running
OVERLAYED_WAIT_TIMEOUT (in seconds) in env: to wait longer. The limit applies to each wait, and they run
one after another: bundle --release waits on the bundle builds, then the app release, then the site release,
and promote --type both on the app, then the site. Keep the job’s timeout-minutes above all of them together,
or GitHub can stop the job between the app and the site.
