Files
coolify/RELEASE.md
T
peaklabs-dev fa128d86c9 feat(release): name the stable CDN pull request after its version
- push the stable channel to sync/stable-v<version> instead of a branch named after the time, a new sync of the same version updates its pull request
- close the open sync pull requests of older stable versions as superseded
- name the commit and the pull request after the version change, like the upstream check of peakimages/sqlite, with a note to squash merge it
2026-11-02 21:55:04 +01:00

10 KiB

Releases

Every release is tagged v<version>, such as v4.6.0-beta.1, and publishes the image with the tag 4.6.0-beta.1 on ghcr.io and Docker Hub.

Important

A push that changes release.json releases the version it sets, unless that version is released already. Run scripts/plan-version.sh first to see what a push releases.

Rules

Branch Takes Releases
main fixes, and next or a release branch for a new version stable versions
next features prereleases of the next minor or major
release/v4.6 the minor 4.6, split off next so next can go on to 4.7 prereleases of 4.6.0
release/v5.0 the next major, cut from next prereleases of 5.0.0
v4.x backports, once main is on v5 stable 4.x versions
v4.4.x backports and hotfixes, cut from the newest tag of v4.4 stable 4.4.x versions
  • main takes fixes only. A new minor or major reaches it as a merge of next or a release branch
  • next and the release branches publish prereleases only, their stable versions are released on main
  • Name a branch after what it changes: fix/<topic>, feat/<topic>, and fix/<topic>-v4.4.8 for a backport, after the version that releases it
  • Squash merge pull requests from contributors and pull requests with a single change, such as dependency updates
  • Merge everything else with a merge commit: team pull requests with several commits, backports, next, the release branches and v4.5.x into main
  • The merge forward workflow merges main into release/v4.6 and next, and release/v4.6 into next
  • While main is on 4.5, v4.3.x and v4.4.x are never merged into another branch
  • Delete release/v4.6 once main has released 4.6.0
  • Delete v4.5.x once it is merged into main
  • Delete v4.3.x and v4.4.x once their release is published, the next backport cuts them again from the newest tag

Caution

Never squash merge next or a release branch. Their commits stay unmerged and come back as conflicts in every later merge.

Create a release

Note

next publishes prereleases only. For its stable version, merge next into main with a merge commit and create the release on main.

  1. Describe the changes under ## [Unreleased] in CHANGELOG.md, they become the release notes

  2. Check what the branch releases:

    scripts/plan-version.sh
    
  3. Select the stage and the version, the script commits them and asks to push:

    scripts/release.sh
    
  4. The pushed commit changes release.json, so it runs the release workflow, which builds and publishes the release and moves its tags

  5. After a stable release that moves latest, merge the pull request of the stable channel on coollabsio/coollabs-cdn, see CDN

Tip

To take the release commit back before the push:

scripts/undo-release.sh

Backport a fix

main is on 4.5, and 4.3 and 4.4 still get fixes. A fix reaches each of them through a patch branch and a pull request of its own:

  1. Cut the patch branch from the newest tag of the minor, unless it exists:

    git switch -c v4.4.x v4.4.7 && git push -u origin v4.4.x
    
  2. Put the fix on a branch named after the version that releases it, cherry-picked from main when it is there already:

    git switch -c fix/<topic>-v4.4.8 origin/v4.4.x && git cherry-pick -x <commit>
    
  3. Merge a pull request from fix/<topic>-v4.4.8 into v4.4.x with a merge commit

  4. Create the release on your checkout of v4.4.x:

    git switch v4.4.x && git pull && scripts/release.sh
    
  5. Repeat with v4.3.x and fix/<topic>-v4.3.25. 4.2 gets no backports

Important

A hotfix for 4.5 while main holds unreleased changes goes through v4.5.x the same way. Merge v4.5.x into main with a merge commit afterwards and delete it. v4.3.x and v4.4.x are never merged, their fixes come from main.

Release a major version

  1. Cut release/v5.0 from next and create its prereleases there with scripts/release.sh:

    git switch -c release/v5.0 origin/next && git push -u origin release/v5.0
    
  2. Merge main into release/v5.0, so v5 has every fix of v4 and the pull request into main has no conflicts:

    git switch release/v5.0 && git pull && git merge origin/main && git push
    
  3. Keep v4 on a branch of its own:

    git switch -c v4.x origin/main && git push -u origin v4.x
    
  4. Merge a pull request from release/v5.0 into main with a merge commit

  5. Create the release on main and select 5.0.0:

    git switch main && git pull && scripts/release.sh
    
  6. Delete release/v5.0

Important

Cut v4.x from main, or bring an existing one up to date with main, before release/v5.0 is merged into main. Afterwards main is v5 and v4 lives on v4.x alone.

Nightlies

The nightly workflow publishes a nightly twice a day when its branch has a new commit, versioned <base>.<YYYYMMDD>.<N>:

State Nightly
nothing bumped since 5.0.4 5.1.0-alpha.0.20261014.1
after 5.1.0-alpha.1 5.1.0-alpha.1.20261014.1
after 5.1.0-beta.1 5.1.0-beta.1.20261014.1
second nightly on the same day 5.1.0-beta.1.20261014.2
after 5.1.0-rc.1 5.1.0-rc.1.20261015.1
after 5.1.0 5.2.0-alpha.0.20261016.1
  • It comes from next, or from the lowest release branch while one is in progress: release/v5.1 takes it over once it is cut and hands it back once 5.1.0 is released
  • The base is the preview version of that branch in release.json while it is ahead of the newest stable version, a plain one with -alpha.0. Otherwise it is the next version with -alpha.0, which is never released. A pull request takes the same base
  • N counts up per day and base
  • No git tag and no GitHub release, only its image tag, the moving nightly tag and the nightly channel of the CDN

Print what the next run publishes with scripts/plan-version.sh --nightly.

Main builds

The main workflow builds main twice a day when it changed since the last build and moves ghcr.io/coollabsio/coolify:main to it, to test fixes before their patch release. A main build is versioned <stable version>.<YYYYMMDD>.<N>, 4.5.0.20261028.1, which sorts after 4.5.0 and before 4.5.1.

  • ghcr.io only, no version tag, no git tag, no GitHub release and no channel of the CDN, an instance installs it through the custom channel with the tag main

Print what the next run builds with scripts/plan-version.sh --main.

Pull requests

The pull request workflow builds every pull request and publishes the image of a pull request from a branch of this repository as ghcr.io/coollabsio/coolify:pr-<number>. Its version is <base>-pr.<number>, with the base a nightly of its base branch takes, or the stable version for main:

  • Into next: 4.6.0-beta.1-pr.1234 after 4.6.0-beta.1, or 4.7.0-alpha.0-pr.1234 before the first alpha of 4.7.0
  • Into main: 4.5.3-pr.1234
  • PHP's version_compare sorts it after its base and the nightlies of the base and before the next prerelease or release, so an instance on it updates to the release that ships it
  • Pull requests from forks and Dependabot are built, not published
  • A push to a pull request from main, next, a release branch or a patch branch that changes release.json is not built, the release workflow builds it
  • Pull request builds are published to ghcr.io only, as the Docker Hub credentials are in the release environment, which no pull request run can use
  • Pull request builds create no git tag and no GitHub release

CDN

scripts/sync-cdn.sh syncs a channel of coollabsio/coollabs-cdn from the commit of the version it syncs: the install and upgrade scripts, the compose files, the environment file, the service templates, the GitHub releases and the block of the channel in /coolify/versions.json.

Channel Path Synced by
stable /coolify/ the release workflow when latest moves, a pull request
preview /coolify/preview/ the release workflow when preview moves, pushed to main
nightly /coolify/nightly/ the nightly workflow after every nightly, pushed to main
  • The preview channel takes betas and release candidates, alphas reach the nightly channel only
  • The stable channel opens a pull request from sync/stable-v<version>, squash merge it. A new sync of the same version updates it, a sync of a newer version closes it
  • CDN_TOKEN in the environment release is a fine-grained token for coollabsio/coollabs-cdn alone, with read and write access to contents and pull requests
  • /coolify/versions.json has a stable, preview and nightly block, each with the Coolify version of its channel and the helper, Sentinel and Traefik versions of the upstream.json it was synced from. An instance takes the newest version of its channel and the more stable ones
  • Every stable sync also sets the coolify and traefik keys, which older instances read, to the stable versions, so older instances upgrade to a version that reads the blocks

Cloudflare keeps a file of the CDN for up to 10 minutes. To clear the cache sooner, for example once the pull request of the stable channel is merged and deployed, set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ZONE_ID in .env or the environment, with a token that can purge the cache of the zone:

scripts/sync-cdn.sh --purge

Update the helper, Sentinel or Traefik

upstream.json pins them. A change of it releases nothing, every Coolify instance reads the versions from the CDN. To ship it before the next release, sync the stable channel on main:

scripts/sync-cdn.sh --stable <latest version>