Cache integration
Collection of skills for the ColdBox Platform and Claude Plugin
npx -y skills add ColdBox/skills --skill cache-integrationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use this skill when implementing caching inside a ColdBox application -- configuring CacheBox via ColdBox.cfc or config/CacheBox.cfc, injecting caches with WireBox (cachebox:name), using getCache() in handlers, event/view output caching with setEventCacheableEntry(), view fragment caching with renderView(cache=true), query caching, cache listeners as ColdBox interceptors, Redis/distributed provider setup, or choosing between default and template caches.
SKILL.md
21.1 KB, ~4.7k tokens by cl100k_base, as published. Nobody here has run it
CacheBox — ColdBox Integration
When to Use This Skill
Use this skill when adding caching to a ColdBox application. For standalone CacheBox usage (no ColdBox framework), see the cachebox-standalone skill.
Language Mode Reference
Examples use BoxLang (.bx) syntax by default. For CFML replace class with component and use property name="x" inject="y"; annotations.
| Concept | BoxLang | CFML |
|---|---|---|
| Class | class { | component { |
| WireBox inject annotation | @inject( "dsl" ) above property | property name="x" inject="dsl"; |
| View files | .bxm | .cfm |
1. How ColdBox Wires CacheBox
ColdBox creates and manages a CacheBox factory automatically. No Application.cfc bootstrap code is needed. The factory is accessible via:
// From any handler, interceptor, or service
var cacheBox = getCacheBox(); // the CacheBox factory
var defCache = getCache(); // default cache provider
var tplCache = getCache( "template" ); // named cache provider
2. Configuration
ColdBox looks for CacheBox config in this order:
cacheboxDSL struct insideconfig/ColdBox.cfc→configure()config/CacheBox.cfc(portable CFC by convention — recommended)- Built-in defaults at
coldbox/system/web/config/CacheBox.cfc
2a. Default built-in caches (no config required)
ColdBox ships with two built-in caches:
| Cache name | Object store | Purpose |
|---|---|---|
default | ConcurrentStore (guaranteed) | General data, objects, query results |
template | ConcurrentSoftReferenceStore (memory-sensitive) | Event output caching, view fragment caching |
Use the defaults until you need different TTLs, size limits, or distributed providers.
2b. config/CacheBox.cfc (recommended for custom config)
// config/CacheBox.cfc
component {
function configure() {
cacheBox = {
// All timeouts in MINUTES
// MANDATORY. "default" is reserved. coldboxEnabled MUST be true in ColdBox apps.
defaultCache : {
objectDefaultTimeout : 60,
objectDefaultLastAccessTimeout : 30,
useLastAccessTimeouts : true,
reapFrequency : 2,
freeMemoryPercentageThreshold : 0,
evictionPolicy : "LRU",
evictCount : 1,
maxObjects : 300,
objectStore : "ConcurrentStore",
coldboxEnabled : true // REQUIRED for ColdBox
},
caches : {
// ColdBox event/view template caching — memory-sensitive is appropriate here
template : {
provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider",
properties : {
objectDefaultTimeout : 60,
objectDefaultLastAccessTimeout : 30,
useLastAccessTimeouts : true,
reapFrequency : 2,
freeMemoryPercentageThreshold : 0,
evictionPolicy : "LRU",
evictCount : 2,
maxObjects : 300,
objectStore : "ConcurrentSoftReferenceStore"
}
},
// Product catalog — long TTL, guaranteed objects
products : {
provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider",
properties : {
objectDefaultTimeout : 240, // 4 hours
maxObjects : 1000,
objectStore : "ConcurrentStore"
}
},
// Session/token cache — match your session timeout
sessions : {
provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider",
properties : {
objectDefaultTimeout : 30,
maxObjects : 5000,
objectStore : "ConcurrentStore"
}
}
}
};
}
}
2c. Inline DSL inside ColdBox.cfc
// config/ColdBox.cfc
function configure() {
// ...other config...
// Option A: point to an external CFC
cacheBox = { configFile : "config.CacheBox" };
// Option B: inline DSL (same keys as portable CFC above)
cacheBox = {
defaultCache : { objectDefaultTimeout : 60, maxObjects : 300, coldboxEnabled : true },
caches : {}
};
}
2d. Engine-native providers (Lucee / Adobe CF caches)
// config/CacheBox.cfc — add after the default caches block
if ( listFindNoCase( "Lucee", server.coldfusion.productname ) ) {
cacheBox.caches.luceeCache = {
provider : "coldbox.system.cache.providers.LuceeColdBoxProvider"
};
} else {
cacheBox.caches.cfCache = {
provider : "coldbox.system.cache.providers.CFColdBoxProvider"
};
}
2e. Redis provider (cbRedis module)
box install cbRedis
// config/CacheBox.cfc
caches : {
redis : {
provider : "cbRedis.models.providers.RedisProvider",
properties : {
host : getSystemSetting( "REDIS_HOST", "localhost" ),
port : getSystemSetting( "REDIS_PORT", 6379 ),
password : getSystemSetting( "REDIS_PASSWORD", "" ),
database : 0,
objectDefaultTimeout : 60,
keyPrefix : "myapp:"
}
},
// Distribute sessions across cluster nodes
sessions : {
provider : "cbRedis.models.providers.RedisProvider",
properties : {
host : getSystemSetting( "REDIS_HOST", "localhost" ),
port : getSystemSetting( "REDIS_PORT", 6379 ),
objectDefaultTimeout : 30,
keyPrefix : "myapp:session:"
}
}
}
3. Injecting Caches with WireBox
Use WireBox DSL to inject cache providers into any managed component (services, handlers, interceptors).
BoxLang:
class ProductService {
// Inject by name — resolves to the named cache provider
@inject( "cachebox:default" )
property name="cache";
@inject( "cachebox:products" )
property name="productCache";
@inject( "cachebox:template" )
property name="templateCache";
// Inject the full CacheBox factory (to resolve caches dynamically)
@inject( "cachebox" )
property name="cacheBox";
function getCacheByName( required string name ) {
return cacheBox.getCache( name )
}
}
CFML:
component {
property name="cache" inject="cachebox:default";
property name="productCache" inject="cachebox:products";
property name="templateCache" inject="cachebox:template";
property name="cacheBox" inject="cachebox";
}
From handlers/interceptors (no injection needed)
// Available directly in handlers and interceptors via controller helpers
var cache = getCache(); // default cache
var tpl = getCache( "template" );
var cacheBox = getCacheBox();
4. Core Cache API (Same for All Providers)
All timeouts are in minutes.
// ── WRITE ────────────────────────────────────────────────────────────────────
cache.set( "product_1", product, 60, 30 ); // TTL=60, idle=30
cache.set( "product_1", product ); // use configured defaults
cache.set( "config", data, 0, 0 ); // eternal
// ── READ ─────────────────────────────────────────────────────────────────────
var val = cache.get( "product_1" ); // null if missing/expired
var val = cache.getQuiet( "product_1" ); // does not reset idle timer
// ── GET-OR-SET ────────────────────────────────────────────────────────────────
var product = cache.getOrSet(
objectKey : "product_1",
produce : function() { return productRepository.findById( 1 ) },
timeout : 60,
lastAccess : 30
);
// ── CHECK ────────────────────────────────────────────────────────────────────
var exists = cache.lookup( "product_1" );
var exists = cache.lookupQuiet( "product_1" ); // no idle reset
// ── DELETE ───────────────────────────────────────────────────────────────────
cache.clear( "product_1" );
cache.clearByKeySnippet( "product_", false ); // all keys containing snippet
cache.clearByKeySnippet( "^product_\d+$", true ); // regex
cache.clearAll();
cache.expireObject( "product_1" ); // lazy expire
// ── INSPECT ──────────────────────────────────────────────────────────────────
var meta = cache.getCachedObjectMetadata( "product_1" );
var keys = cache.getKeys();
var size = cache.getSize();
var stats = cache.getStats();
5. Service-Layer Cache Patterns
Simple cache-aside
BoxLang:
class ProductService {
@inject( "cachebox:products" )
property name="cache";
function getById( required numeric id ) {
var key = "product_#id#"
var product = cache.get( key )
if ( !isNull( product ) ) {
return product
}
product = productRepository.findById( id )
cache.set( key, product, 60, 30 )
return product
}
function list( numeric page = 1, numeric limit = 25 ) {
return cache.getOrSet(
objectKey : "products_list_#page#_#limit#",
produce : function() { return productRepository.list( page = page, limit = limit ) },
timeout : 30,
lastAccess : 15
)
}
function save( required struct product ) {
var saved = productRepository.save( product )
// Write-through
cache.set( "product_#saved.id#", saved, 60, 30 )
// Invalidate related list caches
cache.clearByKeySnippet( "products_list_" )
return saved
}
function delete( required numeric id ) {
productRepository.delete( id )
cache.clear( "product_#id#" )
cache.clearByKeySnippet( "products_list_" )
}
}
CFML:
component {
property name="cache" inject="cachebox:products";
function getById( required numeric id ) {
return cache.getOrSet(
objectKey : "product_#id#",
produce : function() { return productRepository.findById( id ) },
timeout : 60,
lastAccess : 30
)
}
}
Stampede protection
function getExpensiveValue( required string key, required any loader, numeric timeout = 60 ) {
var value = cache.get( key )
if ( !isNull( value ) ) { return value }
lock name="cache_load_#key#" timeout="15" throwontimeout="false" type="exclusive" {
value = cache.get( key )
if ( isNull( value ) ) {
value = loader()
cache.set( key, value, timeout )
}
}
return value
}
6. Event Output Caching
Cache the entire output of a handler event. ColdBox stores the rendered HTML in the template cache provider.
BoxLang:
class Catalog extends coldbox.system.EventHandler {
function index( event, rc, prc ) {
// Cache this event's output for 60 min, idle 30 min
event.setEventCacheableEntry(
provider : "template",
timeout : 60,
lastAccess : 30
)
prc.categories = categoryService.list()
event.setView( "catalog/index" )
}
function show( event, rc, prc ) {
// Cache per product ID — different cache entry per suffix
event.setEventCacheableEntry(
provider : "template",
timeout : 120,
lastAccess : 60,
suffix : rc.id ?: "0"
)
prc.product = productService.getById( rc.id ?: 0 )
event.setView( "catalog/show" )
}
}
CFML:
component extends="coldbox.system.EventHandler" {
function index( event, rc, prc ) {
event.setEventCacheableEntry(
provider : "template",
timeout : 60,
lastAccess : 30
)
prc.categories = categoryService.list()
event.setView( "catalog/index" )
}
}
Invalidation: Event caches are keyed by event name + suffix. Clear them via
getCache( "template" ).clearByKeySnippet( "event_name" )orgetCache( "template" ).clearAll().
7. View Fragment Caching
Cache individual view fragments inside a layout or view template. Uses the template cache.
// In a view or layout file (.bxm / .cfm)
#renderView(
view = "shared/featured_products",
cache = true,
cacheTimeout = 30,
cacheLastAccessTimeout = 15
)#
Fragment cache keys are auto-generated from the view path. Clear a fragment:
getCache( "template" ).clearByKeySnippet( "shared/featured_products" )
8. Query Caching (native CFML)
ColdFusion/Lucee/BoxLang natively cache queries with cachedWithin:
function getTopProducts() {
return queryExecute(
"SELECT * FROM products WHERE active = 1 ORDER BY views DESC LIMIT 10",
{},
{
cachedWithin : createTimeSpan( 0, 0, 30, 0 ), // 30 minutes
datasource : "myapp"
}
)
}
Use CacheBox provider caching (not query-level) when you need explicit invalidation control.
9. Cache Listeners as ColdBox Interceptors
In ColdBox, CacheBox listeners are ColdBox interceptors — declare them in config/ColdBox.cfc.
BoxLang:
// interceptors/CacheAuditInterceptor.bx
class CacheAuditInterceptor extends coldbox.system.Interceptor {
function configure() {}
// ── CacheBoxProvider events ───────────────────────────────────────────
function afterCacheElementInsert( event, interceptData, buffer ) {
log.debug(
"CACHE INSERT [#interceptData.cache.getName()#] #interceptData.cacheObjectKey# ttl=#interceptData.cacheObjectTimeout#"
)
}
function afterCacheElementRemoved( event, interceptData, buffer ) {
log.debug(
"CACHE REMOVE [#interceptData.cache.getName()#] #interceptData.cacheObjectKey#"
)
}
function afterCacheElementExpired( event, interceptData, buffer ) {
log.debug(
"CACHE EXPIRE [#interceptData.cache.getName()#] #interceptData.cacheObjectKey#"
)
}
// ── CacheFactory events ───────────────────────────────────────────────
function afterCacheFactoryConfiguration( event, interceptData, buffer ) {
log.info( "CacheBox configured" )
// Good place to warm caches
warmCriticalCaches()
}
function beforeCacheFactoryShutdown( event, interceptData, buffer ) {
log.warn( "CacheBox shutting down" )
}
private function warmCriticalCaches() {
var cache = getCacheBox().getCache( "products" )
var products = productGatewayInstance.findAllActive()
for ( var p in products ) {
cache.set( "product_#p.id#", p, 240, 60 )
}
}
}
CFML:
component extends="coldbox.system.Interceptor" {
function configure() {}
function afterCacheElementInsert( event, interceptData, buffer ) {
log.debug( "INSERT [#interceptData.cache.getName()#] #interceptData.cacheObjectKey#" )
}
function afterCacheFactoryConfiguration( event, interceptData, buffer ) {
// Warm critical caches after CacheBox starts
}
}
Register in config/ColdBox.cfc:
interceptors = [
{ class : "interceptors.CacheAuditInterceptor", name : "CacheAuditInterceptor", properties : {} }
];
10. CacheBox Events Available to Interceptors
CacheFactory events
| Event | interceptData keys |
|---|---|
afterCacheFactoryConfiguration | cacheFactory |
beforeCacheFactoryShutdown | cacheFactory |
afterCacheFactoryShutdown | cacheFactory |
afterCacheRegistration | cache |
beforeCacheRemoval | cache |
afterCacheRemoval | cache (name string) |
beforeCacheReplacement | oldCache, newCache |
beforeCacheShutdown | cache |
afterCacheShutdown | cache |
CacheBoxProvider events
| Event | interceptData keys |
|---|---|
afterCacheElementInsert | cache, cacheObject, cacheObjectKey, cacheObjectTimeout, cacheObjectLastAccessTimeout |
afterCacheElementUpdated | cache, cacheNewObject, cacheOldObject |
afterCacheElementRemoved | cache, cacheObjectKey |
afterCacheElementExpired | cache, cacheObjectKey |
afterCacheClearAll | cache |
11. Named Cache Configuration Reference
defaultCache properties
| Property | Type | Default | Description |
|---|---|---|---|
objectDefaultTimeout | numeric | 60 | Object lifespan (minutes); 0 = eternal |
objectDefaultLastAccessTimeout | numeric | 30 | Idle timeout (minutes) |
useLastAccessTimeouts | boolean | true | Enable/disable idle timeout |
reapFrequency | numeric | 2 | Minutes between expiry sweeps |
freeMemoryPercentageThreshold | numeric | 0 | Min JVM free memory % before caching (0=unlimited) |
evictionPolicy | string | LRU | LRU, LFU, FIFO, LIFO, or custom path |
evictCount | numeric | 1 | Objects evicted per policy execution |
maxObjects | numeric | 300 | Maximum live objects |
objectStore | string | ConcurrentStore | ConcurrentStore, ConcurrentSoftReferenceStore, DiskStore, JDBCStore |
coldboxEnabled | boolean | true | Must be true for ColdBox default cache |
resetTimeoutOnAccess | boolean | false | Reset TTL on each access (session-like behaviour) |
12. Production Best Practices
- Set
coldboxEnabled : truein thedefaultCacheblock — required for ColdBox app integration. - Use the
defaultcache for service/data caching and thetemplatecache exclusively for event/view output. - Inject caches at component level via WireBox (
@inject( "cachebox:name" )) — never callgetCache()inside methods if the component is a WireBox singleton. - Prefer
getOrSet()at the service layer to eliminate null-check boilerplate. - Use
getCache()/getCacheBox()inside handlers and interceptors — these controller helpers spare the injection overhead for one-off use. - Event output caching is coarse-grained — it caches entire event HTML; hard to selectively invalidate. Use only for read-heavy, infrequently updated pages.
- View fragment caching is finer-grained than event caching — prefer it over event caching when only part of a page is static.
- Configure Redis for multi-server / auto-scaling deployments — in-memory providers are per-process.
- Namespace cache keys by domain and ID (
"product_#id#","user_#id#_prefs") to avoid cross-domain collisions. - Use
clearByKeySnippet()to invalidate families of keys; avoidclearAll()which evicts everything and causes stampede. - Warm critical caches in the
afterCacheFactoryConfigurationinterceptor event — fires after ColdBox starts CacheBox. - Monitor
getStats()per cache to tune TTL andmaxObjects; low hit rates usually mean TTL is too short or keys are not reused. - Never cache user-specific data with a shared key — always include user identity in the cache key.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most project setup skills give in ~4.7k tokens
Counted across 999 of the 1,637 authors here whose files we hold, read 2026-08-07
- Ask one question at a timein 29 of 999, across 28 files
- Detect the package manager from lockfilesin 28 of 999, across 9 files
- Present findings to the userin 26 of 999, across 5 files
- Explore current repo statein 24 of 999, across 3 files
- Update the agent skills block in place if it existsin 24 of 999, across 3 files
- Install husky lint-staged and prettierin 23 of 999, across 4 files
- Create the lintstagedrc filein 22 of 999, across 3 files
- Commit all changed filesin 22 of 999, across 3 files
- Run lint-staged to verify it worksin 22 of 999, across 3 files
- Create the husky pre-commit filein 21 of 999, across 2 files
- Create a prettierrc file if missingin 21 of 999, across 2 files
- Initialize huskyin 21 of 999, across 2 files
Said here and by no other author read
- use built-in caches until custom configuration is required
- set coldboxEnabled to true for default cache
- use the template cache for event output caching
- use ConcurrentSoftReferenceStore for template caches
- use WireBox DSL to inject cache providers
- use cachebox:default to inject the default cache
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.