The cache()
function in @joystick.js/node
provides a simple API for managing caches on the server in your app. This utility is useful for temporarily storing data (e.g., frequently accessed records or ephemeral data) that you want to avoid repeatedly fetching or recalculating during runtime.
Caches automatically use Redis as the storage backend if Redis is configured with cache: true
in your app's settings, otherwise they fall back to in-memory storage. Both backends support TTL (Time To Live) and LRU (Least Recently Used) eviction policies.
Caches can be defined anywhere on your server, however, the recommended approach is to store each cache definition as a single file in the caches
folder at the root of your project and import them into your index.server.js
file to pass to the caches()
function passed to your joystick.app()
via its options object.
Example Usage
Defining a cache
caches/example.js
import { cache } from '@joystick.js/node';
const users_cache = cache('users');
To define a cache, we import the named export cache
from @joystick.js/node
and then call it, passing the name of our cache()
. In response, we get a cache instance with a few different methods for managing the cache.
Setting a cache
caches/example.js
import { cache } from '@joystick.js/node';
const users_cache = cache('users');
users_cache.set([
{ id: '1', name: 'Alice', role: 'admin' },
{ id: '2', name: 'Bob', role: 'editor' },
]);
Above, to set a default value for a cache (or overwrite the entirety of an existing cache), we can use the cache.set()
method. To it, we pass an array of objects representing the new value we want to set for the cache.
Finding one or all items in a cache
caches/example.js
import { cache } from '@joystick.js/node';
const users_cache = cache('users');
// Find all users
const all_users = users_cache.find();
// Find users with role 'editor'
const editors = users_cache.find(['role', 'editor']);
// Find a single user by ID
const user = users_cache.find_one(['id', '2']);
Above, we call .find()
on a cache to return the full, current cache. To find items matching a specific query, we can call .find()
passing an array where the first element is the name of the field on the cache item we want to match and the second element is the value for the field on the cache itme we want to match. If we want a single, specific item, we can use the .find_one()
method, using the same array-based querying.
Updating a cache
caches/example.js
import { cache } from '@joystick.js/node';
const users_cache = cache('users');
users_cache.update(['id', '2'], { role: 'superadmin' });
Above, we update a specific item in the cache, first passing an array-style query like we use with the .find()
method and then as the second argument, an object containing the modifications we'd like to make to the cache item matching the query passed as the first argument.
Removing items from a cache
caches/example.js
import { cache } from '@joystick.js/node';
const users_cache = cache('users');
users_cache.remove(['id', '1']);
To remove a specific item(s) from the cache, again, we deploy the array-style query syntax we used with the other methods above. Note: this will remove any cache items matching the query, not just the first one to match.
Redis Support
Caches automatically use Redis as the storage backend when Redis is configured in your app's settings with cache: true
. This provides several benefits:
- Shared across processes: Multiple app instances can share the same cache
- Persistent: Cache survives app restarts
- Efficient: Uses Redis native data structures for optimal performance
Configuring Redis for caching
settings.development.json
{
"config": {
"databases": [
{
"provider": "redis",
"cache": true,
"options": {}
}
]
}
}
TTL and LRU Policies
Both in-memory and Redis caches support Time To Live (TTL) and Least Recently Used (LRU) eviction policies:
TTL (Time To Live)
Items automatically expire after the specified time:
caches/session.js
import { cache } from '@joystick.js/node';
// Items expire after 5 minutes (300 seconds)
const session_cache = cache('sessions', { ttl: 300 });
session_cache.add({ user_id: '123', token: 'abc...' });
// Item will be automatically removed after 5 minutes
LRU (Least Recently Used)
Cache maintains a maximum number of items, removing the least recently accessed:
caches/users.js
import { cache } from '@joystick.js/node';
// Keep maximum 1000 items, remove oldest when exceeded
const user_cache = cache('users', { max_items: 1000 });
user_cache.add({ id: '1', name: 'Alice' });
// When 1001st item is added, least recently used item is removed
Combining TTL and LRU
caches/api_responses.js
import { cache } from '@joystick.js/node';
// Items expire after 10 minutes AND keep max 500 items
const api_cache = cache('api_responses', {
ttl: 600, // 10 minutes
max_items: 500 // Maximum 500 items
});
api_cache.add({ endpoint: '/users', data: [...] });
// Item will be removed after 10 minutes OR when LRU limit is exceeded
How LRU tracking works
- Items are marked as "accessed" when retrieved via
find()
orfind_one()
- Items are marked as "accessed" when updated via
update()
- When
max_items
is exceeded, the least recently accessed items are removed first - Redis: Uses sorted sets for efficient LRU tracking
- In-memory: Uses timestamps for LRU tracking
API
cache()
cache(cache_name: string, options?: object) => object
Parameters
- cache_name string required
-
A string to uniquely identify the cache in
process.caches
. Used as the key to store and retrieve cache data. - options object
- Optional configuration object for TTL and LRU policies.
cache.add()
cache.add(cache_item: object) => void
Parameters
- cache_item object required
- The object to add to the cache array.
cache.find()
cache.find(query_array: [string, any]) => array
Parameters
- query_array array
-
An array with two elements:
[key, value]
. Only cache items matching this key/value pair will be returned. If omitted, all items in the cache are returned.
cache.find_one()
cache.find_one(query_array: [string, any]) => object|null
Parameters
- query_array array
-
An array with two elements:
[key, value]
. Only the first cache item matching this key/value pair will be returned. If omitted, returnsnull
.
cache.set()
cache.set(cache_array: array) => void
Parameters
- cache_array array required
- An array of objects to set as the entire cache contents. Overwrites any existing cache data.
cache.update()
cache.update(match_array: [string, any], replacement_item: object) => void
Parameters
- match_array array required
-
An array with two elements:
[key_to_match, value_to_match]
. Identifies the cache item to update. - replacement_item object required
- The object to merge into the matched cache item.
cache.remove()
cache.remove(match_array: [string, any]) => void
Parameters
- match_array array required
-
An array with two elements:
[key_to_match, value_to_match]
. Identifies the cache items to remove.