Releases RSS

Wheels 4.1.0 is out — the release a bug report built

Wheels 4.1.0 is out. If you’ve followed the series, you know this release has a plot, and it starts with @chapmandu asking, politely, whether we’d ever benchmarked Wheels 4 against 2.5.

He’d ported a real app. His test suite went from five minutes to half an hour. And as it turned out, he was right. That single report is the reason this isn’t just another features-and-fixes release — it’s the reason the framework got meaningfully faster, and the reason a couple of hard-to-find bugs are gone.

Full notes: GitHub Release v4.1.0 · CHANGELOG

The features, and what they’re really about

bcrypt password hashing. bcryptHash(), bcryptVerify(), bcryptNeedsRehash() — bundled jBCrypt for speed with a pure-CFML fallback when the jar isn’t available, OpenBSD/htpasswd/jBCrypt-compatible, correct on every engine. The deep dive starts with a pentest report, but it’s really about the migration dance you’ll do to use them.

One-line session auth. injector().enableSession() in config/services.cfm. The story is the three subtle bugs it exists to prevent — the strategy that isn’t there, the duplicate, the logged-in-user-who-isn’t.

Pretty routes. bindBy="slug" turns /posts/4821 into /posts/wheels-4-1-released. The deep dive is the unshareable link and the two ways to get it wrong.

DI factories. toFactory() for when to() can’t express how something gets built. The story is the service that couldn’t decide where its files lived.

CLI workflow tools. migrate diff, generate --dry-run, offline mode, fail-closed exit codes. The story is two deploy incidents and the CLI learning to show its work.

The centerpiece: performance

Model instantiation is ~2.5× faster than 4.0.3 on our benchmark rig — the result of the investigation @chapmandu’s report started. Request-scoped plan caching, compile-time inheritance of the model API, and direct construction instead of a DI round-trip and a reflective invoke. The full story — including the two unrelated bugs the benchmarking surfaced — is in the write-up.

The hardening pass

4.1 also ships a release-cycle security hardening: fail-closed policies and auth, controller retargeting protection, strict mass-assignment mode, zip-slip and path-escape fixes, view-helper encoding, middleware copy semantics, storage key validation. The theme is one word: fail closed. Area by area.

And the rest

  • Developer tooling: a Code Complexity panel and the wheels coverage CRAP-ranking command — the tool that would have caught the September bug.
  • Engine compatibility: the Adobe CF 2023/2025 matrix failures are fixed, the core suite runs clean on the JVM-free RustCFML engine, and the Adobe applicationStop() teardown crash (“Element wo is undefined”, which could error a whole site until a CF restart) is gone — onApplicationEnd, onSessionEnd, and onError now survive a torn-down application scope.
  • Deploy: Kamal-compatible boot config (limit/wait).
  • Deprecations: wheels.Test (RocketUnit) now warns once; removal is planned for Wheels 5.0. If you still run RocketUnit suites, that’s your heads-up.

Upgrading

wheels upgrade check
wheels upgrade apply

The upgrade is additive — the behavior-changing items are opt-in (strict mass assignment, sanitizeHref, JWT requireExpiry) or bug fixes to documented defaults. The changelog’s “changed” section is the complete list of the latter; it’s a ten-minute read and worth doing before you deploy.

One manual step if you run Adobe CF 2023/2025: the teardown hardening ships in public/Application.cfc, which the vendor/wheels/ swap doesn’t touch. wheels upgrade check now flags that drift automatically — diff your public/Application.cfc against the bundled template and adopt the guarded onError/onSessionEnd handlers before you deploy. (Lucee and BoxLang apps are unaffected.)

The thanks

Releases usually end with thanks to the people who filed the issues. This one means it more than most. @chapmandu asked a question we should have been asking ourselves, and the answer reshaped the framework — not just its speed, but how we’ll measure it next time.

If you’re on an older 4.0.x and your suite got slower somewhere along the way, this is the release to try. And if it’s still slow, file it. The rig is built, and it’s listening before it argues.

Comments

Newsletter

Release notes and new posts, once a month. No spam.

Prefer RSS? Subscribe to the feed →