i18n usually arrives as an emergency. wheels-i18n makes the mechanical part boring: t() and tp() with interpolation and pluralization, JSON or database catalogs, session-based locale switching, and the fallback chain that makes incremental translation actually shippable.
Most developers use a fifth of the debug bar and writeDump() around the rest. The full tour: what each panel answers, the developer tools behind the last tab, the throughput cost worth knowing, and why the bar can't follow you to production — by design.
Declare fullName or commentCount once as SQL on the model and it behaves like a column everywhere — sortable, selectable, never stale. And Wheels 4's select=false + includeCalculated pair fixes the cost problem calculated properties always created: expensive expressions run only where they're asked for, additively.
A REPL inside your running app: models resolve, scopes chain, the DI container answers, settings read back. The sessions that replace writeDump-and-refresh archaeology, the slash-commands, and why console and repl are different tools that look alike.
SSE gives you the pipe; channels answer the harder question — how the model callback that knows something happened reaches the connection three requests away. publish(), subscribeToChannel(), channelSSETag(), the memory-vs-database adapter decision, and the named-event gotcha that catches almost everyone.
findAll on 400,000 rows materializes everything into memory at once — and the request cache holds it there. Wheels 4's findEach and findInBatches walk big result sets a page at a time, with three built-in optimizations you'd forget to hand-roll and two sharp edges worth knowing first.
CommandBox teams do not have to switch. The complete box-native workflow for Wheels 4 — install from ForgeBox, engine selection with cfengine, datasources via CFConfig, every framework task's in-app equivalent, CI with setup-commandbox, and an honest accounting of what the wheels CLI adds if you ever want it.
Why exporting WHEELS_ENV=production doesn't flip your app into production — and everything else about the config pipeline: the three-file load order, the .env chain that shadows OS variables, what production mode really changes, and the reload gate's fail-closed mechanics.
Three small pieces of plumbing turn 'the site gave me an error around lunchtime' into a single grep: the RequestId middleware, the /up health endpoint your app already ships, and a forty-line JSON logging pattern. Plus the two health-endpoint mistakes everyone makes once.
Wheels 4 denies cross-origin requests until you say otherwise — and the Cors middleware refuses the popular ways of saying it wrong. The deny-all breaking change, single-origin resolution, Vary: Origin, preflight handling, and the legacy-settings trap the framework defuses for you.
Wheels 4 ships session, API-token, and JWT authentication as pluggable strategies behind one Authenticator registry. Wiring up all three doors — with the sharp edges: private filters, dynamic finders, the 32-byte JWT secret minimum, and the inline-closure constructor that crashes Adobe ColdFusion.
The manual install that took the community two days to reverse-engineer in Wheels 3 is now two zip files and zero external dependencies. How to install, migrate, test, seed, and upgrade a Wheels 4 app with no CLI, no CommandBox, and no package manager — plus the new guides that document every step.
A complete how-to for sending email in Wheels 4.0 — the sendEmail controller helper, how email view templates resolve, multipart text+html, attachments, and the correct way to deliver mail from a background job. Includes the sharp edges that actually bite.
Wheels 4.0 has no ActiveStorage-style attachment system — and that's fine. This how-to walks the honest idiomatic upload flow end to end: fileField/fileFieldTag form helpers, the startFormTag multipart trap, native cffile in the controller, model validation over the result, and traversal-safe downloads with sendFile.
A practical, source-grounded tour of every cache Wheels 4.0 actually ships — action caching, query caching, partial and page caching — plus the honest truth about invalidation: there's no clearCache(key), so you live on short expiry times and full reloads.
A comprehensive Wheels 4.0 guide to model associations — hasMany, belongsTo, and hasOne, the exact dynamic methods each one generates, dependent-delete cascades, nested properties from form params, eager loading with include=, has-many-through, and polymorphic associations — with the sharp edges that bite in practice.
A worked how-to on Wheels 4.0 form helpers: object-bound fields that round-trip into params.user.email, the real HTML5 single-input helpers, and the two error-rendering helpers — plus the sharp edges that bite first.
A practical Wheels 4.0 guide to the full validation surface — conditional rules with condition/unless/when, custom validate() methods, enum() integration, and how to read the error API correctly. Built end-to-end around one User model, with every behavior grounded in the framework source.
A complete Wheels 4.0 routing guide — RESTful resources, nested resources via callback vs manual nested=true, and route model binding that resolves params.post before your action runs. Plus the sharp edges: route order, the protected-helper-names trap, and how a missing record 404s.
Wheels 4.0 ships a convention-based seeder built around seedOnce() — an idempotent helper that creates a record only if a matching one doesn't already exist, wrapped in a transaction that rolls the whole run back on any failure. This is the worked guide: file conventions, the CLI, composite uniqueness, and the sharp edges.
A user-facing how-to for the Wheels 4.0 DI container: register services in config/services.cfm with singleton/request/transient scopes, resolve them anywhere with service(), declare them in controllers with inject(), and let constructor auto-wiring fill in the rest.
A from-scratch guide to authoring custom middleware in Wheels 4.0 — the one-method interface, the singleton-per-app lifecycle and the thread-safety it demands, how to short-circuit, and how to register globally or per route.
A complete how-to on Wheels 4.0's paginationNav helper — the all-in-one nav, the bootstrap5/bootstrap4/tailwind preset system, the auto/always/never anchor tri-state, and the dev-time guardrails that catch typos before they ship.
A worked guide to Wheels 4.0's Server-Sent Events helpers — renderSSE for one-shot events, the initSSEStream/sendSSEEvent/closeSSEStream trio for long-lived streams, plus isSSERequest content negotiation, keep-alive heartbeats, and the engine-fragility sharp edges to test for.
Wheels 4.0 ships three model-side features that compose into one design: scopes name reusable query fragments, enums turn property values into auto-generated checkers and scopes, and the chainable query builder swaps raw WHERE strings for fluent, type-aware composition. This post walks all three through one worked example and surfaces the bug I hit while writing it.
Wheels 4.0.5 is out, and together with 4.0.4 it's one of the most substantial hardening passes on the 4.0 line — 100+ changes spanning security (open-redirect and info-disclosure fixes, fail-closed gates, SQL-surface tightening), warm-path performance, a much tougher `wheels deploy`, and Adobe CF / BoxLang cross-engine fixes. 4.0.5 then makes the whole thing installable the same way on every major platform — Homebrew, Scoop, apt, dnf — including arm64 Linux, verified daily.
Wheels 4.0 ships a stdio MCP server that exposes the CLI to AI editors — not as a chat sidekick, but as a tool surface a model can call. This post walks the architecture (reflection over a single CFC), builds a commenting feature end-to-end via Claude, and is honest about the config-template drift I hit while writing it.
A broad how-to on the Wheels 4.0 migrator: write up()/down() migrations, drive the TableDefinition column builder (including the three-column timestamps() and the columnNames-preferred helpers), seed with inline SQL, and run the migrate CLI — including the doctor/info/forget/pretend commands that keep a shared dev database honest.
Wheels 4.0 replaces plugins with a package system that treats your filesystem as the registry. This post takes a small package from empty directory to installed-and-mixed-in, names every field in the manifest, and is honest about the rough edges I hit while writing it.
Wheels 4.0.3 is the third patch on the 4.0 line, focused on making the `wheels` CLI trustworthy in scripts and CI: argument parsing is rebuilt end-to-end (`--no-*` negations and named-only flags finally reach every command), failures exit non-zero, and write-side commands refuse to attach to a different project's server. Plus PostgreSQL/CockroachDB foreign-key migration fixes, pre-23c Oracle support, preserved column casing in model output, and a fix that stops framework helpers from being URL-invokable as controller actions.
Wheels 4.0.2 is the second patch on the 4.0 line. It teaches the migrator how to cope with a database that more than one developer shares — orphan-version detection, a `migrate doctor` health report, and `forget` / `pretend` reconciliation commands — fixes a class of silent migration rollbacks on MSSQL, makes the migrator's column-name helpers consistent, and ships native signed apt.wheels.dev / yum.wheels.dev package repositories so Linux installs and upgrades are a one-liner.
Wheels 4.0.1 is out — the first patch on the 4.0 line. It hardens Adobe ColdFusion 2023/2025 compatibility, fixes the Windows Scoop install regressions reported after GA, adds CSS-framework presets to paginationNav(), short-circuits whereIn([]) so empty filters stop emitting invalid SQL, and threads about a hundred smaller fixes through the rest of the framework.
Wheels 4.0 ships a real middleware pipeline, and three of the things you used to reach for a plugin to add — rate limiting, CORS, and security headers — are built in. This post walks through wiring a JSON API with per-API-key rate limits, sane proxy handling, and the right ordering so you do not accidentally weaken the very headers you were trying to add.
Wheels 4.0 decomposes the framework's rim against the CFML engine, pulls dependency injection and the test runner in-house as wheelsdi and WheelsTest, and breaks the monolithic boot sequence into discrete phases. Nothing a user of the framework notices at the surface. Everything a contributor notices when they try to add the next feature.
Wheels 4.0 lands with seven breaking changes and a Legacy Compatibility Adapter for teams that cannot touch every call site this quarter. This post is the honest map: what breaks, how to detect it, how to fix it, and when the adapter is the right answer instead.
For years, the same rows showed up red in every framework comparison: no bulk ops, no polymorphic associations, no advisory locks, no middleware, no browser testing. Wheels 4.0 closes those gaps. This is a guided tour of what changed and where the framework still trails.
Wheels 4.0 ships with a new inner-loop story: a single native binary, a sixty-second full test run, and a multi-phase migration that quietly moved the framework off Docker for day-to-day development. This post walks through how we got here, what LuCLI is, and why cross-engine matrix testing still belongs in Docker.
Wheels 4.0 lifts multi-tenancy out of plugin territory and into the framework core. Per-request datasource switching catches every query and every job on the way to the database, and tenant-aware background jobs come along for the ride.
Wheels 4.0 ships a production-ready job queue that needs only your database. You get a persistent CLI worker, live monitoring, configurable backoff, and tenant-aware enqueueing without any extra services. Redis still wins for very high throughput and pub/sub fan-out — this post names where the DB-backed queue is the right call and where it is not.
Wheels 4.0 completes the test pyramid: BDD unit tests, a fluent HTTP TestClient for integration, and Playwright-powered browser automation for end-to-end — all running in parallel. The category that was most embarrassing in 3.0 is the most complete in 4.0.
Wheels 4.0 shipped more than forty security-hardening pull requests across eight categories — SQL, path handling, session integrity, CORS, rate limiting, auth and dev surfaces, CLI and MCP, and view helpers. The common thread is a shift in posture: the framework's defaults are now safe first, convenient second.
Wheels 4.0 ships with a new command: wheels deploy. It's a port of Basecamp's Kamal into the Wheels CLI — zero-downtime Dockerized deploys to Linux servers over plain SSH, no Ruby runtime required. This post covers what got ported, the one deliberate divergence from Kamal, and the byte-compatibility contract that lets you take over a Kamal-managed server without cleanup.