| title | Release Channels | ||
|---|---|---|---|
| description | Choose between Wheels stable and bleeding-edge — and switch between them. | ||
| type | explanation | ||
| sidebar |
|
import { Aside, Tabs, TabItem, Steps, CardGrid, LinkCard } from '@astrojs/starlight/components';
Wheels ships on two parallel channels. Pick the one that matches how much churn you can absorb.
| 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) |
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.11
Note the command is wheels version (no dashes). The flag form wheels --version prints a Wheels Version: <version> line plus ASCII art, with no channel parenthetical.
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.
brew tap wheels-dev/wheels
# Stable
brew install wheels
# Bleeding-edge
brew 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
# Stable
scoop install wheels
# Bleeding-edge
scoop 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.gpg
echo "deb [signed-by=/usr/share/keyrings/wheels.gpg] https://apt.wheels.dev stable main" \
| sudo tee /etc/apt/sources.list.d/wheels.list
sudo apt update && sudo apt install wheelssudo dnf config-manager --add-repo https://yum.wheels.dev/wheels.repo
sudo dnf install wheelscurl -fsSL https://apt.wheels.dev/wheels.gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/wheels.gpg
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.list
sudo apt update && sudo apt install wheels-besudo dnf config-manager --add-repo https://yum.wheels.dev/wheels-be.repo
sudo 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).
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 wheels
brew install wheels-bebrew uninstall wheels-be
brew 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.list
sudo 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 wheels
sudo dnf config-manager --add-repo https://yum.wheels.dev/wheels-be.repo
sudo 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-be
sudo 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-be
sudo dnf install wheelsscoop uninstall wheels
scoop install wheels-bescoop uninstall wheels-be
scoop install wheelsAlready-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 first
wheels upgrade apply # swap vendor/wheels/ from the CLI bundle (creates backup)…or re-scaffold the app's vendor/wheels/ from a fresh wheels new.
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.
This section is for the curious. If you just want to use Wheels, you can skip it.
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.
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.
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.