From boxlang-agent-skills
Use this skill when implementing caching in BoxLang applications: cache providers, cachePut/cacheGet BIFs, output caching, cache regions, distributed caching with Redis or Couchbase, TTL policies, and distributed locking.
How this skill is triggered — by the user, by Claude, or both
Slash command
/boxlang-agent-skills:cachingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
BoxLang provides a flexible, pluggable caching system managed by `CacheService`.
BoxLang provides a flexible, pluggable caching system managed by CacheService.
Multiple named cache regions can coexist, each backed by a different provider.
The default in-memory cache is available immediately; Redis, Couchbase, JDBC, and
filesystem caches are available via modules.
boxlang.json{
"caches": {
"default": {
"provider": "BoxCacheProvider",
"properties": {
"maxObjects": 1000,
"defaultTimeout": 60,
"defaultLastAccessTimeout": 30,
"reapFrequency": 5,
"evictionPolicy": "LRU"
}
},
"sessions": {
"provider": "BoxCacheProvider",
"properties": {
"maxObjects": 5000,
"defaultTimeout": 120
}
},
"queries": {
"provider": "jdbc",
"properties": {
"datasource": "mainDB",
"table": "cache_entries"
}
},
"files": {
"provider": "filesystem",
"properties": {
"directory": "/tmp/bxcache"
}
}
}
}
// Store a value (default cache, 60-minute TTL)
cachePut( "user_#userId#", userStruct )
// Store with explicit TTL (timespan)
cachePut( "user_#userId#", userStruct, createTimeSpan( 0, 1, 0, 0 ) ) // 1 hour
// Store with TTL and idle timeout
cachePut(
"user_#userId#",
userStruct,
createTimeSpan( 0, 2, 0, 0 ), // absolute TTL: 2 hours
createTimeSpan( 0, 0, 30, 0 ) // idle timeout: 30 minutes
)
// Retrieve
var user = cacheGet( "user_#userId#" )
if ( isNull( user ) ) {
user = userService.findById( userId )
cachePut( "user_#userId#", user, createTimeSpan( 0, 1, 0, 0 ) )
}
// Check existence without fetching
if ( cacheKeyExists( "user_#userId#" ) ) {
// ...
}
// Remove
cacheRemove( "user_#userId#" )
// Remove multiple
cacheRemove( ["user_1", "user_2", "user_3"] )
// Clear all entries in default cache
cacheClear()
// Use a specific named cache
cachePut( "product_#id#", product, createTimeSpan(0,4,0,0), "", "products" )
var product = cacheGet( "product_#id#", false, "products" )
// Check in named cache
if ( cacheKeyExists( "product_#id#", "products" ) ) { ... }
// Clear a specific cache region
cacheClear( "products" )
// Get cache statistics
var stats = cacheGetStats( "products" )
writeOutput( "Hits: #stats.hits#, Misses: #stats.misses#, Size: #stats.size#" )
// List all cache IDs
var keys = cacheGetAllIds( "products" )
// Reusable cache-aside helper
function cacheOrLoad(
required string key,
required function loader,
any ttl = createTimeSpan(0,1,0,0),
string cacheName = "default"
) {
var cached = cacheGet( arguments.key, false, arguments.cacheName )
if ( !isNull( cached ) ) {
return cached
}
var fresh = arguments.loader()
cachePut( arguments.key, fresh, arguments.ttl, "", arguments.cacheName )
return fresh
}
// Usage
var config = cacheOrLoad(
key = "app_config",
loader = () -> configService.loadFromDB(),
ttl = createTimeSpan(0,0,15,0) // 15 minutes
)
Cache rendered HTML output to avoid re-executing expensive templates:
// Cache entire block output for 10 minutes
bx:cache timespan=createTimeSpan(0,0,10,0) {
// Expensive rendering
var products = queryExecute("SELECT * FROM products")
for ( var p in products ) {
include "views/product-card.bxm"
}
}
// With a custom cache key
bx:cache timespan=createTimeSpan(0,0,5,0) id="dashboard_#session.userId#" {
renderDashboard()
}
// Named cache region for output
bx:cache timespan=createTimeSpan(0,1,0,0) cacheName="pages" {
renderHomePage()
}
// boxlang.json — configure Redis cache
{
"modules": {
"bx-redis": {
"enabled": true,
"settings": {
"host": "${REDIS_HOST:localhost}",
"port": "${REDIS_PORT:6379}",
"password": "${REDIS_PASSWORD:}",
"database": 0
}
}
},
"caches": {
"distributed": {
"provider": "redis",
"properties": {
"defaultTimeout": 300,
"keyPrefix": "myapp:"
}
}
}
}
// Use Redis cache transparently via the same API
cachePut( "session_#token#", sessionData, createTimeSpan(0,2,0,0), "", "distributed" )
var sessionData = cacheGet( "session_#token#", false, "distributed" )
Prevent cache stampede with distributed locks:
// Only one process rebuilds the cache at a time
bx:lock name="rebuild_product_cache" type="exclusive" timeout=30 {
// Double-check after acquiring the lock
var cached = cacheGet( "all_products" )
if ( isNull( cached ) ) {
var products = queryExecute( "SELECT * FROM products" )
cachePut( "all_products", products, createTimeSpan(0,0,30,0) )
}
}
// boxlang.json
{
"modules": {
"bx-couchbase": {
"enabled": true,
"settings": {
"servers": ["couchbase://localhost"],
"bucket": "myapp",
"username": "${COUCH_USER}",
"password": "${COUCH_PASS}"
}
}
},
"caches": {
"docStore": {
"provider": "couchbase",
"properties": {
"defaultTimeout": 3600
}
}
}
}
| Policy | Description |
|---|---|
LRU | Least Recently Used (default) |
LFU | Least Frequently Used |
FIFO | First-In, First-Out |
Random | Random eviction |
// Application.bx
boolean function onApplicationStart() {
// Pre-load frequently accessed data
var config = configService.loadAll()
cachePut( "app_config", config, createTimeSpan(1,0,0,0) )
var categories = queryExecute( "SELECT * FROM categories" )
cachePut( "categories", categories, createTimeSpan(0,4,0,0) )
return true
}
// Tag-based invalidation (group related keys)
function invalidateUserCache( required numeric userId ) {
cacheRemove( "user_#userId#" )
cacheRemove( "user_profile_#userId#" )
cacheRemove( "user_permissions_#userId#" )
cacheRemove( "user_orders_#userId#" )
}
// Versioned cache keys (avoids stampedes)
function getCacheKey( required string base ) {
var version = cacheGet( "v:#base#" ) ?: 1
return "#base#:v#version#"
}
function invalidateVersion( required string base ) {
var current = cacheGet( "v:#base#" ) ?: 1
cachePut( "v:#base#", current + 1, createTimeSpan(1,0,0,0) )
}
cacheGetOrSet — Atomic Get-or-LoadcacheGetOrSet() atomically returns a cached value or executes a loader closure
and stores the result if no entry exists:
// Signature: cacheGetOrSet( key, valueFunction, timeout, cacheName )
var settings = cacheGetOrSet(
"appSettings",
() => settingService.loadAll(),
60 // minutes
)
// With named cache region
var product = cacheGetOrSet(
"product_#id#",
() => queryExecute( "SELECT * FROM products WHERE id = :id", { id: id }, { returntype: "struct" } ),
createTimeSpan( 0, 1, 0, 0 ),
"products"
)
cachedWithinCache query results directly in queryExecute() options:
// Cache for 1 hour — result is reused on subsequent calls
var users = queryExecute(
"SELECT * FROM users WHERE isActive = 1",
{},
{ cachedWithin: createTimeSpan( 0, 1, 0, 0 ) }
)
// Cache with a named key (use cacheRemove() to invalidate)
var products = queryExecute(
"SELECT * FROM products ORDER BY name",
{},
{
cacheName : "productList",
cachedWithin : createTimeSpan( 0, 0, 30, 0 )
}
)
// Invalidate manually when data changes
function updateProduct( required numeric id, required struct data ) {
queryExecute( "UPDATE products SET name = :name WHERE id = :id",
{ name: data.name, id: id } )
cacheRemove( "productList" )
}
Use the cachedWithin function attribute to cache a function's return value
based on its arguments:
// Method result cached per unique argument set for 1 hour
function fibonacci( required numeric n ) cachedWithin=createTimeSpan( 0, 1, 0, 0 ) {
if ( n <= 1 ) return n
return fibonacci( n - 1 ) + fibonacci( n - 2 )
}
// Manual in-memory memoization (no TTL)
class ExpensiveService {
variables.memo = {}
function compute( required numeric id ) {
if ( memo.keyExists( id ) ) return memo[ id ]
var result = runExpensiveCalculation( id )
memo[ id ] = result
return result
}
}
npx claudepluginhub ortus-boxlang/skills --plugin boxlang-agent-skillsProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.