Start Here
Release Channels
Wheels ships on two parallel channels. Pick the one that matches how much churn you can absorb.
Stable vs bleeding-edge at a glance
Section titled “Stable vs bleeding-edge at a glance”| Stable | Bleeding-edge | |
|---|---|---|
| Package name | wheels | wheels-be |
| Tracks | GA tags on main | Snapshot pre-releases on develop |
| Update cadence | When a new GA ships (~quarterly) | On every merge to develop (multiple per day during active development) |
| Source repo | wheels-dev/wheels | wheels-dev/wheels-snapshots |
| Best for | Production apps, teams that want predictability | Framework contributors, early adopters, validating fixes before they GA |
| Version string shape | 4.0.0, 4.1.0 | 4.0.1-snapshot.1700 |
wheels version reports | (stable) | (bleeding-edge) |
How to tell which channel you’re on
Section titled “How to tell which channel you’re on”wheels versionThe output’s parenthetical tells you the channel:
Wheels 4.0.3 (stable)Java 21.0.11…or:
Wheels 4.0.0-snapshot.1787 (bleeding-edge)Java 21.0.11Note the command is wheels version (no dashes). The flag form wheels --version varies by install method — Homebrew stable and manual JAR installs print a Wheels Version: <version> banner plus ASCII art with no channel, while the apt/yum and Homebrew bleeding-edge package wrappers print a one-line wheels <version> (<channel>). wheels version is the form that reports the channel reliably everywhere.
If you see (development) instead, you’re running from a dev checkout (cloned source repo) rather than an installed package — which is its own thing and not covered here.
Installing each channel
Section titled “Installing each channel”brew tap wheels-dev/wheels
# Stablebrew install wheels
# Bleeding-edgebrew install wheels-beHomebrew 5.1+ asks you to trust third-party taps on first use — run brew trust wheels-dev/wheels once if prompted (one trust covers both formulas).
The two formulas are mutually exclusive — both expose the wheels binary, so Homebrew refuses to install both at once. To switch channels, uninstall one and install the other (see Switching channels below).
Both channels are available via a Scoop bucket:
scoop bucket add wheels https://github.com/wheels-dev/scoop-wheels
# Stablescoop install wheels
# Bleeding-edgescoop install wheels-beThe two packages are mutually exclusive — both expose the wheels binary, so Scoop refuses to install both at once. To switch channels, uninstall one and install the other (see Switching channels below). Both inline OpenJDK 21, so no separate Java setup is needed — see Installing Wheels → Windows for the Scoop + git prerequisites.
Each channel ships from a signed native repository — distinct package names (wheels vs wheels-be) so both channels can coexist on the same host:
- Stable:
https://apt.wheels.dev stable main/https://yum.wheels.dev/wheels.repo→ packagewheels - Bleeding-edge:
https://apt.wheels.dev bleeding-edge main/https://yum.wheels.dev/wheels-be.repo→ packagewheels-be
curl -fsSL https://apt.wheels.dev/wheels.gpg \ | sudo gpg --dearmor -o /usr/share/keyrings/wheels.gpgecho "deb [signed-by=/usr/share/keyrings/wheels.gpg] https://apt.wheels.dev stable main" \ | sudo tee /etc/apt/sources.list.d/wheels.listsudo apt update && sudo apt install wheelssudo dnf config-manager --add-repo https://yum.wheels.dev/wheels.reposudo dnf install wheelscurl -fsSL https://apt.wheels.dev/wheels.gpg \ | sudo gpg --dearmor -o /usr/share/keyrings/wheels.gpgecho "deb [signed-by=/usr/share/keyrings/wheels.gpg] https://apt.wheels.dev bleeding-edge main" \ | sudo tee /etc/apt/sources.list.d/wheels-be.listsudo apt update && sudo apt install wheels-besudo dnf config-manager --add-repo https://yum.wheels.dev/wheels-be.reposudo dnf install wheels-beBoth repos are GPG-signed (fingerprint 6872 16C9 32B4 9F03 94E0 9AED 5D89 AF8F 9C9B 8CFB); apt update / dnf check-update verifies the signature on every refresh. The published key is ASCII-armored, so the Debian/Ubuntu snippet pipes it through sudo gpg --dearmor — apt rejects an armored key written straight to a signed-by= keyring. The raw .deb/.rpm are also uploaded to each GitHub Release as a fallback for air-gapped installs (see CLI Installation).
Switching channels
Section titled “Switching channels”On macOS and Windows, the channels publish two differently-named packages (wheels vs wheels-be) that both install a binary called wheels, so the package managers refuse to install both at once — Homebrew enforces this via conflicts_with, Scoop refuses outright.
On Linux, the two channels likewise publish differently-named packages: wheels (stable, from wheels-dev/wheels) and wheels-be (bleeding-edge, from wheels-dev/wheels-snapshots). Switching = installing the package from the other repo. The wheels-be .deb declares Replaces: wheels + Conflicts: wheels, so on Debian/Ubuntu apt handles the stable → bleeding-edge swap automatically. The wheels-be .rpm declares only Conflicts: (no Obsoletes:), and the stable wheels package doesn’t declare either against wheels-be, so the dnf direction and the reverse (bleeding-edge → stable) both need an explicit remove step. Snippets below cover each case.
brew uninstall wheelsbrew install wheels-bebrew uninstall wheels-bebrew install wheels# Add the bleeding-edge source (uses the same key already imported for stable).# wheels-be .deb declares Replaces: wheels + Conflicts: wheels, so apt removes# the stable wheels package and installs wheels-be in its place — no separate# `apt remove` needed.echo "deb [signed-by=/usr/share/keyrings/wheels.gpg] https://apt.wheels.dev bleeding-edge main" \ | sudo tee /etc/apt/sources.list.d/wheels-be.listsudo apt update && sudo apt install wheels-be# wheels-be .rpm declares Conflicts: wheels but no Obsoletes, so dnf# refuses to install while the stable wheels package is present. Remove# it first, then add the bleeding-edge .repo source and install.sudo dnf remove wheelssudo dnf config-manager --add-repo https://yum.wheels.dev/wheels-be.reposudo dnf install wheels-be# wheels-be declares Conflicts: wheels, so apt refuses to install wheels# while wheels-be is present. Remove wheels-be, then install wheels —# both come from the same apt.wheels.dev source list, so no extra setup# is needed.sudo apt remove wheels-besudo apt install wheels# Same as Debian above — wheels-be declares Conflicts: wheels, so dnf# refuses to install wheels while wheels-be is present. Remove wheels-be# first, then install wheels. Both come from yum.wheels.dev (stable# lives at wheels.repo, bleeding-edge at wheels-be.repo); the stable# .repo file is left in place from the original install.sudo dnf remove wheels-besudo dnf install wheelsscoop uninstall wheelsscoop install wheels-bescoop uninstall wheels-bescoop install wheelsWhat happens to your apps when you switch
Section titled “What happens to your apps when you switch”Already-scaffolded apps are unaffected. Each Wheels app commits its own copy of the framework into vendor/wheels/ at scaffold time, so the version baked into your project is independent of what channel your CLI is on. Switching wheels → wheels-be only affects what next wheels new produces.
If you want an existing app to follow the channel switch:
wheels upgrade check --to=<version> # scan for breaking changes firstwheels upgrade apply # swap vendor/wheels/ from the CLI bundle (creates backup)…or re-scaffold the app’s vendor/wheels/ from a fresh wheels new.
When to pick which
Section titled “When to pick which”Pick stable (wheels) when:
- You’re shipping a production app
- You want predictable upgrade windows (one major release per ~quarter, see Upgrading Wheels)
- You don’t want to think about CI breaking from upstream churn
- You’re following the tutorial — it’s pinned to stable behavior
Pick bleeding-edge (wheels-be) when:
- You’re contributing to Wheels and want to dogfood your changes
- You’re validating that an upcoming fix lands correctly before GA
- You’re early-adopting a feature that’s merged but not yet released
- You’re OK with the occasional regression (we revert quickly, but the window exists)
If you’re not sure, install stable. You can always switch later — your apps come with you.
How the channels work under the hood
Section titled “How the channels work under the hood”This section is for the curious. If you just want to use Wheels, you can skip it.
What “snapshot” means
Section titled “What “snapshot” means”A snapshot is an automated pre-release built and published on every merge to the develop branch. The version string 4.0.0-snapshot.1787 decodes as:
4.0.0— the target of the next release (a baseline, not a commitment — the actual GA could end up being4.0.0,4.0.1,4.1.0, or whatever the maintainer picks at tag time)-snapshot— SemVer pre-release identifier (sorts strictly less than4.0.0).1787—github.run_numberof the workflow that built it (monotonically increasing)
So brew upgrade wheels-be always lands on a numerically-newer snapshot, and any GA release sorts strictly higher than every snapshot that preceded it.
Where snapshots live
Section titled “Where snapshots live”Snapshots publish to wheels-dev/wheels-snapshots instead of the main repo’s Releases page. The split keeps the main repo’s Releases page focused on GA tags (~6–12 per year) instead of drowning them under snapshot churn (~200–500 per year). Snapshots auto-delete after 30 days; GA releases stay forever.
Auto-update propagation
Section titled “Auto-update propagation”When a snapshot publishes:
- The release workflow on
wheels-dev/wheelsdispatches awheels-releasedevent to the brew tap withchannel=bleeding-edgein the payload. - The tap’s
bleeding-edge-update.ymlworkflow fires, computes fresh sha256s, opens an auto-bump PR forFormula/wheels-be.rb. - Tap CI validates the formula (
brew audit+brew fetch), maintainer rubberstamps, the PR auto-merges. brew upgrade wheels-belands the new version on user machines.
End-to-end latency: ~5–10 minutes from develop merge to user-installable.
For stable releases, the same chain runs against Formula/wheels.rb and the auto-update.yml workflow.