Upgrade Guide
Introduction
Reepolee upgrades work differently from most frameworks because Reepolee isn't a dependency. There's no npm install reepolee@latest to run; during closed alpha, you receive a tagged release archive through the alpha channel, and the version that archive was cut from is the version you're working with. Upgrading means requesting a newer archive and bringing its changes into your own project - usually a clean merge, occasionally a small migration if a public-facing pattern has changed.
This page covers the general flow, what kinds of changes constitute breaking changes, and the version-by-version migration steps when one is needed. The current state of each release is in Release Notes.
The Upgrade Philosophy
Reepolee's approach to versioning trades some convenience for a property we care about: upgrades shouldn't surprise you. A few things follow from that:
- Zero runtime dependencies - the framework can't break because a transitive dependency shipped a regression. Reepolee can only break because Reepolee changed.
- You own the framework code -
lib/,components/,config/db.ts, the generator. If an upgrade adjusts a function signature inlib/render.ts, the change is right there in your repo to read; nothing innode_modulesis mysteriously different. - Templates and generated code are stable - once
bun generator/resource crud userswritesroutes/users/index.ts, that file is yours forever. Upgrades don't reach into generated routes. - Breaking changes are minimal and explicit - when one is necessary, it's documented in the release notes and on this page with the exact steps to take. The default expectation is "merge in the new archive, resolve any merge conflicts in customised files, run."
This shape is what lets a project from a year ago still build today without you doing anything other than bun install and bun run css:build.
The General Upgrade Flow
Because a Reepolee project is a plain folder with your own git history rather than a fork, the cleanest way to upgrade is to keep the pristine framework on a branch of its own and merge new releases from there into your working branch. Set that up once, from the archive you started with:
# One time: a branch that holds the unpacked archive, untouched
git switch --orphan reepolee-vanilla
# unpack the archive you started from into this empty working tree, then:
git add -A && git commit -m "Reepolee (vanilla)"
git switch main
To upgrade, request the newer .tar.gz through the alpha channel, unpack it over the vanilla branch, commit, and merge it into your work:
git switch reepolee-vanilla
# unpack the new reepolee.tar.gz over this working tree, overwriting files
git add -A && git commit -m "Reepolee 26.08.1 (vanilla)"
git switch main
git merge reepolee-vanilla
# Resolve any merge conflicts (see below), then run the deploy sequence
bun install --frozen-lockfile
bun run css:build
Conflicts almost always happen in three places:
routes.ts- your route registrations vs new routes the template added.sql/sqlite//sql/mysql/- your schema vs the template's. Almost always wins your version; the template's seed data is for the demo.- Translation rows - keys you've added vs new keys the template ships.
Framework code (lib/, components/, config/db.ts) rarely conflicts because most projects don't edit those files. When it does, take the new release's version - your customisations to those files belong in your own modules anyway.
After resolving conflicts, the deploy commands stay identical. There's no "post-upgrade migration" step because there's no framework state to migrate.
What Counts as a Breaking Change
The following are breaking and get explicit migration steps below:
- Renamed or removed functions in
lib/orroutes/system/auth/that you might have imported. - Removed or renamed translation keys that templates reference.
- Schema changes to the
sessions,users, oremailtables that an existing database needs to match. - Renamed configuration constants in
config/db_structure.ts. - Behaviour changes in
render(),create_ctx(),resolve_session(), or any of the middleware exports.
The following are not breaking and don't need migration:
- New files added under
lib/,components/,routes/system/auth/. Take them or leave them. - New optional fields on existing options objects (e.g., a new optional argument to
send_mail). - Bug fixes that change observable but undocumented behaviour.
- Internal refactors within
lib/files where the public surface is unchanged. - Changes to
config/db.ts- internal refactors don't change which database you connect to; that's controlled byCONNECTION_STRINGin your.env.
When in doubt, the Release Notes for the version describe what's changed.
Upgrading Across Releases
Point releases within a month (26.07.1 → 26.07.2) are bug fixes and documentation only - the general upgrade flow covers them with no extra steps. A new month's release (26.07.x → 26.08.1) is a feature release and may carry a breaking change; when it does, the steps appear here under a dated "From 26.07.x to 26.08.1" heading. None are documented yet.
For the current state of the latest release, see the release notes entry.
Upgrading Bun
Reepolee tracks Bun's stable releases. Upgrading Bun itself is independent of upgrading Reepolee:
bun upgrade # latest stable
bun upgrade --canary # latest canary build
Reepolee pins a Bun version in its README's "Bun version" line. Run with a Bun version that's the pinned version or newer; older versions may be missing APIs Reepolee uses (Bun.password, Bun.SQL, the import-text attribute, Bun.redis).
For long-running production servers, pinning Bun explicitly avoids surprises. The systemd unit calls Bun by absolute path (/home/deploy/.bun/bin/bun) - running bun upgrade updates that binary in place. To pin a specific version, install it explicitly:
curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.13"
Then leave it alone until you've tested an upgrade in a non-production environment.
Reporting an Upgrade Issue
If an upgrade breaks something that isn't documented as a breaking change, that's a bug - open an issue at github.com/reepolee/reepolee/issues with:
- The version you upgraded from and the version you upgraded to.
- The actual error or unexpected behaviour.
- The smallest reproduction (a route, a template, a config snippet).
We track upgrade-breaking-without-warning issues with high priority because the trust that an upgrade is safe is the property the whole versioning approach rests on.