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 when env.useFSCache is true and filesystem access is available (Node/Deno/Bun), defaulting to ./.cache/ relative to the project root.
  • Browser Cache API: Activated when env.useBrowserCache is true and the Cache API is available, storing data under the key defined in env.cacheKey (default: 'transformers-cache').
  • Custom Cache: Activated when env.useCustomCache is true and env.customCache is assigned an object implementing the match and put interface.

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, then ModelRegistry.get_model_files() to populate the cache before user requests.
  • Persistent cache strategies are configured via env.cacheDir, env.useFSCache, env.useBrowserCache, and env.useCustomCache in src/env.js, with backends implemented in src/utils/cache.js.
  • Cache verification is available through ModelRegistry.is_pipeline_cached(), returning an allCached boolean and per-file status.
  • Cache invalidation uses ModelRegistry.clear_cache() or ModelRegistry.clear_pipeline_cache() to remove specific models or task configurations.
  • Custom storage implements the match/put interface and registers via env.customCache when env.useCustomCache is 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →