Preloading Models at Startup and Managing Persistent Cache Strategies in Transformers.js
Preloading models at startup in Transformers.js involves using ModelRegistry.get_pipeline_files() to identify required assets, then eagerly loading them via ModelRegistry.get_model_files() or pipeline initialization, while persistent caching is handled through configurable backends in src/utils/cache.js that respect env.cacheDir and cache flags.
When building production web applications with Hugging Face Transformers.js, eliminating cold-start latency requires strategic preloading and persistent storage of model weights. The library implements a sophisticated caching architecture centered on src/utils/hub.js for file retrieval and src/utils/cache.js for backend selection, enabling granular control over model asset persistence across Node.js, Deno, Bun, and browser environments.
How Model Loading and Caching Work Under the Hood
The Loading Pipeline
When you call pipeline() or load a model directly, the library orchestrates file retrieval through a specific chain of operations in src/utils/hub.js. The getModelFile() function builds resource paths and delegates to loadResourceFile(), which first checks for cached assets via checkCachedResource() before initiating network requests. After fetching, storeCachedResource() persists the data to the selected backend. This flow ensures that subsequent requests for identical model files—whether ONNX weights, tokenizers, or configuration files—resolve instantly from local storage.
Cache Backend Selection
The getCache() function in src/utils/cache.js dynamically selects a storage implementation based on environment variables defined in src/env.js:
- Filesystem Cache (
FileCache): Activated whenenv.useFSCacheistrueand filesystem access is available (Node/Deno/Bun), defaulting to./.cache/relative to the project root. - Browser Cache API: Activated when
env.useBrowserCacheistrueand the Cache API is available, storing data under the key defined inenv.cacheKey(default:'transformers-cache'). - Custom Cache: Activated when
env.useCustomCacheistrueandenv.customCacheis assigned an object implementing thematchandputinterface.
You can override default locations before any model requests:
import { env } from '@huggingface/transformers';
// Node.js: custom directory
env.cacheDir = '/var/lib/myapp/models';
// Browser: custom storage key
env.cacheKey = 'my-production-cache';
ModelRegistry Discovery API
The src/utils/model_registry/ModelRegistry.js class provides static methods essential for preloading models at startup:
ModelRegistry.get_pipeline_files(task, modelId, options): Returns the complete list of files required for a specific pipeline task (model weights, tokenizer files, generation configs).ModelRegistry.is_pipeline_cached(task, modelId): Reports whether all required files exist in the current cache backend.ModelRegistry.clear_cache(modelId, options): Removes cached files for a specific model configuration.
Preloading Models at Startup
Eager Loading with ModelRegistry
To eliminate first-inference latency, resolve the file list for your target model and trigger downloads before user interaction. This pattern ensures the cache is primed:
import { ModelRegistry } from '@huggingface/transformers';
async function preloadGenerationModel() {
const modelId = 'Xenova/gpt2-onnx';
const task = 'text-generation';
const options = { dtype: 'q4', device: 'webgpu' };
// 1. Discover required files
const files = await ModelRegistry.get_pipeline_files(task, modelId, options);
// 2. Download all files in parallel (cache side-effect)
await Promise.all(
files.map((file) => ModelRegistry.get_model_files(modelId, options))
);
// 3. Verify cache status
const status = await ModelRegistry.is_pipeline_cached(task, modelId);
console.log('Cache primed:', status.allCached);
}
Calling ModelRegistry.get_model_files() triggers the underlying getModelFile() logic for each required asset, storing them in the configured cache without loading the full model into memory.
Preloading via Pipeline Initialization
Alternatively, instantiate the pipeline at application startup and retain the instance. The first pipeline() call downloads and caches all necessary files:
let generator;
async function initializePipeline() {
generator = await pipeline('text-generation', 'Xenova/gpt2-onnx', {
dtype: 'q4',
device: 'webgpu',
progress_callback: (info) => {
console.log(`[${info.status}] ${info.file}`);
},
});
}
// Execute at startup
await initializePipeline();
// Subsequent calls use cached files
const output = await generator('Hello world');
Managing Persistent Cache Strategies
Configuring Cache Behavior
Control persistence and storage location through the env object before any model operations:
| Setting | Default | Description |
|---|---|---|
env.cacheDir |
./.cache/ (Node) |
Filesystem path for model storage |
env.useFSCache |
true (if FS available) |
Enable filesystem persistence |
env.useBrowserCache |
true (if Cache API available) |
Enable browser Cache API |
env.cacheKey |
'transformers-cache' |
Browser cache storage key |
These flags are evaluated at runtime by getCache() in src/utils/cache.js, allowing dynamic configuration based on deployment environment.
Clearing Cached Files
To force fresh downloads or reclaim storage, use the ModelRegistry clearing methods:
// Clear specific model configuration
await ModelRegistry.clear_cache('Xenova/gpt2-onnx', { dtype: 'q4' });
// Clear only files for a specific pipeline task
await ModelRegistry.clear_pipeline_cache('text-generation', 'Xenova/gpt2-onnx');
Both methods return statistics including filesDeleted and filesCached, enabling UI feedback for cache management interfaces.
Implementing Custom Cache Backends
For advanced scenarios like IndexedDB versioning or eviction policies, implement the CacheInterface:
class IndexedDBCache {
async match(key) {
// Return Response, FileResponse, or string path
}
async put(key, response, progressCallback) {
// Store in IndexedDB
}
}
import { env } from '@huggingface/transformers';
env.useCustomCache = true;
env.customCache = new IndexedDBCache();
Once registered, all model file operations route through your custom implementation, bypassing the default filesystem and browser caches.
Complete Startup Script Example
This pattern combines configuration, preloading, and pipeline initialization for a production-ready setup:
import { pipeline, ModelRegistry, env } from '@huggingface/transformers';
// Configure cache before any model operations
env.cacheDir = process.env.MODEL_CACHE_DIR || './.cache';
env.useFSCache = true;
const MODELS = [
{ task: 'text-generation', id: 'Xenova/gpt2-onnx', opts: { dtype: 'q4' } },
{ task: 'image-classification', id: 'Xenova/vit-base-patch16-224', opts: {} },
];
// Preload all models to warm the cache
async function warmCache() {
for (const { task, id, opts } of MODELS) {
const files = await ModelRegistry.get_pipeline_files(task, id, opts);
await Promise.all(
files.map(() => ModelRegistry.get_model_files(id, opts))
);
console.log(`Cached ${id} for ${task}`);
}
}
// Initialize reusable pipelines
const pipelines = {};
async function initPipelines() {
for (const { task, id, opts } of MODELS) {
pipelines[task] = await pipeline(task, id, opts);
}
}
// Startup sequence
await warmCache();
await initPipelines();
// Application ready: all models cached and loaded
Summary
- Preloading models at startup requires calling
ModelRegistry.get_pipeline_files()to identify assets, thenModelRegistry.get_model_files()to populate the cache before user requests. - Persistent cache strategies are configured via
env.cacheDir,env.useFSCache,env.useBrowserCache, andenv.useCustomCacheinsrc/env.js, with backends implemented insrc/utils/cache.js. - Cache verification is available through
ModelRegistry.is_pipeline_cached(), returning anallCachedboolean and per-file status. - Cache invalidation uses
ModelRegistry.clear_cache()orModelRegistry.clear_pipeline_cache()to remove specific models or task configurations. - Custom storage implements the
match/putinterface and registers viaenv.customCachewhenenv.useCustomCacheis enabled.
Frequently Asked Questions
How do I check if a model is already cached before preloading?
Call await ModelRegistry.is_pipeline_cached(task, modelId) or await ModelRegistry.is_cached(modelId, options) to verify cache status without triggering downloads. These methods return an object containing allCached (boolean) and detailed file status, allowing you to skip preloading for already-cached assets.
Can I use different cache locations for different models?
While env.cacheDir sets a global filesystem path for Node.js environments, you cannot specify per-model cache directories directly. However, you can implement a custom cache backend via env.customCache that routes different model IDs to different storage locations based on your own logic in the match and put methods.
What happens if I disable all cache flags in env?
Setting env.useFSCache = false, env.useBrowserCache = false, and env.useCustomCache = false forces getCache() in src/utils/cache.js to return a null cache. In this mode, every model request fetches fresh data from the Hugging Face Hub or local filesystem, eliminating persistence but ensuring you always retrieve the latest model versions.
How do I force a specific model to re-download?
Use await ModelRegistry.clear_cache(modelId, options) with the exact options object (including dtype, device settings, etc.) used during the original download. This removes the cached entries from the active backend. The next request for that model configuration will fetch fresh files from the remote Hub.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →