What's New With 8.2.0
August 17, 2026
ColdBox 8.2.0 is a feature release focused on request-level composition and control: route-scoped middleware, standards-based HTTP caching, first-class Server-Sent Events, and conversational context for AI routing — plus a security hardening fix, a handful of correctness fixes, and hot-path performance work in the Renderer and routing layers.
Major Highlights
🧵 Route-Scoped Middleware — .middleware()
Routes can now carry their own middleware chain instead of relying solely on app-wide interceptors. .middleware() attaches a closure, a WireBox ID, or any object with a method named after the interception point (preProcess by default, or postProcess) to a single route — reusing the same dispatch mechanism ColdBox interceptors already use, just scoped to one route.
route( "/admin/:action" )
.middleware( function( event, rc, prc ){
if ( !auth.isLoggedIn() ) {
event.relocate( "login" );
return true; // short-circuits the rest of this route's middleware
}
} )
.toHandler( "admin" );Two companion features round this out:
middlewareGroup( name, [ ...targets ] )— register a named, reusable bundle once, then reference it by name from.middleware()or agroup()'smiddlewareoption, instead of repeating the same target list everywhere..withoutMiddleware( target )— opt a single route out of middleware it would otherwise inherit, by target name, by the group name it expanded from, or"*"for everything.
middlewareGroup( "api", [ "RequireApiKey", "RateLimiter" ] );
group( { pattern : "/api", middleware : [ "api" ] }, function(){
route( "/users" ).toHandler( "users" ); // runs "api"
route( "/health" ).withoutMiddleware( "api" ).toHandler( "health" ); // opts out
} );🗄️ HTTP Caching Primitives — ETag, Last-Modified, Cache-Control
Standards-based conditional-GET support, usable from any handler:
event.etag()/event.lastModified()— set the corresponding header and short-circuit with a304 Not Modifiedon a match. Never short-circuits an unsafe HTTP method.event.cacheControl()— build aCache-Controlheader from a directives struct.Response.withETag()/Response.withCacheControl()— the same primitives, as fluent methods on the RESTResponseobject.An already
cache="true"event handler action can opt into an automatically computedETag/Last-Modifiedwith newetag/etagWeak/lastModified/cacheControlannotations, piggybacking on event caching with no extra per-request work.
See HTTP Caching.
📡 First-Class Server-Sent Events (BoxLang)
Streaming is now a first-class concern instead of something bolted onto AI routing. event.sse() takes over the response and hands your callback an SSEEmitter with send(), sendView(), sendData(), sendError(), keep-alives, and graceful disconnect handling:
For routes that always stream, Router.toSSE() mirrors toResponse(). Three new interception points (preSSEConnection, postSSEConnection, onSSEError) let you reject a connection before it opens, observe stream completion, or react to mid-stream errors, and a new this.sse settings block controls keep-alive interval, reconnect hints, and CORS defaults.
See Server-Sent Events and Streaming Routes (SSE).
🤖 AI Routing Gets Conversational Context
toAi()'s invoke, stream, and batch sub-routes now resolve userId, conversationId, and threadId from the request body and thread them through to the runnable via options:
userIddefaults to the framework's own session/request tracking identifier when not suppliedconversationIdis passed through only if supplied - no default is inventedthreadIdis generated if not supplied, and is always echoed back - in the JSON response, anX-Thread-Idheader, and a leadingevent: threadSSE frame on/stream(since browserEventSourceclients can't read response headers)
This release also corrects the toAi() reference documentation, which had drifted from the actual run()/stream()-based IAiRunnable interface and request/response shapes. See AI Routing.
🔒 Hardened HTTP Method Spoofing
The _method form-field override (GET/POST browsers use to fake PUT/PATCH/DELETE) is now only honored when the original transport-level request is a POST. Previously, a plain GET request carrying ?_method=DELETE was silently treated as a DELETE — enabling CSRF-style attacks via a link, an <img> tag, a crawler, or a browser prefetch. A new event.getOriginalHTTPMethod() returns the raw, un-spoofed verb when you need it. See HTTP Method Spoofing.
⚡ Renderer & Routing Performance
A new
viewDiscoveryCachingsetting (on by default, independent ofviewCaching) caches the filesystem work that locates view/layout files, benefiting every render regardless of whether view output caching is enabled. See View Discovery Caching.Several hot-path costs eliminated in
HandlerService,RoutingService, andRouter— a per-request settings lookup that should have been cached at configuration time, a redundant filesystem check in view dispatch detection, and route response placeholders now pre-parsed once at registration instead of re-parsed by regex on every matching request.The interceptor chain now reports short-circuiting:
announce()returnstrueon the synchronous path when an interceptor short-circuited the chain,falseotherwise - previously this was undetectable. See Announcing Interceptions.
Release Notes
New Features
COLDBOX-1415 HTTP caching primitives - ETag, Last-Modified, Cache-Control
COLDBOX-1416 Route-scoped middleware via existing interceptor points
COLDBOX-1417 Conversational context (userId/conversationId/threadId) on toAi() routes
First-class Server-Sent Events streaming - event.sse(), SSEEmitter, Router.toSSE(), interception points, this.sse settings (#676)
Improvements
COLDBOX-1406 HTTP method spoofing restricted to POST requests only; new getOriginalHTTPMethod()
New viewDiscoveryCaching setting plus Renderer hot-path caching for view/layout discovery (#664)
Hot-path performance optimizations in HandlerService, RoutingService, and Router (#665)
Interceptor chain now reports and honors short-circuiting via announce()'s return value; new getRouteDefinitionKeys() route-table introspection helper (#677)
Bugs
COLDBOX-1407 url.results collision breaking cache.getOrSet() on any page loaded with ?results=...
COLDBOX-1411 this.EVENT_CACHE_SUFFIX closures were evaluated once and frozen instead of per-request, letting different requests share a cache key
DataMarshaller component made thread-safe (#672)
Fixed a startup typo in Bootstrap.cfc (#667)
Last updated
Was this helpful?