# Managing Multiple Pipeline Instances and Sharing Model Weights in Transformers.js

> Learn to manage multiple pipeline instances and share model weights in Transformers.js. Load once, reuse `PreTrainedModel` for efficient ONNX sessions and reduced memory usage.

- Repository: [Hugging Face/transformers.js](https://github.com/huggingface/transformers.js)
- Tags: best-practices
- Published: 2026-03-03

---

**Load your model once using `AutoModel.from_pretrained()`, then inject that same `PreTrainedModel` instance into multiple pipeline constructors to share ONNX sessions and eliminate redundant memory allocation.**

When building applications that require several AI tasks simultaneously—such as running both text generation and sentiment analysis—loading separate model weights for each pipeline wastes memory and compute. The [`huggingface/transformers.js`](https://github.com/huggingface/transformers.js/blob/main/huggingface/transformers.js) library separates model loading from pipeline construction, making it straightforward to manage multiple pipeline instances efficiently and share model weights across different tasks. By understanding the internal architecture of the model registry, session construction, and pipeline factory, you can optimize resource usage in browser and Node.js environments.

## Architecture Overview: How Transformers.js Handles Model Loading

The library organizes model management into distinct layers that make weight sharing possible. Understanding these layers helps you identify exactly where reuse occurs in the codebase.

### Model Discovery and Cache Handling

The `ModelRegistry` class in [`src/utils/model_registry/ModelRegistry.js`](https://github.com/huggingface/transformers.js/blob/main/src/utils/model_registry/ModelRegistry.js) determines which files belong to a model and checks local cache status. When you call `ModelRegistry.get_files()` or the task-specific `get_pipeline_files()`, the registry walks the model repository and builds a file list such as `["config.json", "onnx/model_q4.onnx"]`.

To verify if a model is already cached locally, use `ModelRegistry.is_cached()`, which internally calls `check_files_cache()` from [`src/utils/model_registry/is_cached.js`](https://github.com/huggingface/transformers.js/blob/main/src/utils/model_registry/is_cached.js). This allows you to check storage status before initiating downloads.

### Session Construction

The heavy computational work happens in `constructSessions()` located in [`src/utils/model-loader.js`](https://github.com/huggingface/transformers.js/blob/main/src/utils/model-loader.js) (line 49). This function receives the list of model file names, calls `getSession()` for each, and creates ONNX `InferenceSession` objects via `createInferenceSession()`.

These sessions are cached inside the `PreTrainedModel` instance within the `this.sessions` property. Because this construction involves reading model files and initializing GPU/CPU contexts, doing it once and reusing the result provides significant performance benefits.

### Pipeline Factory

The public `pipeline()` function in [`src/pipelines.js`](https://github.com/huggingface/transformers.js/blob/main/src/pipelines.js) relies on `loadItems()` (line 14) to lazily load components. The `loadItems()` function creates a mapping of component names to concrete classes, then loads each in parallel:

```javascript
async function loadItems(mapping, model, pretrainedOptions) {
    const result = Object.create(null);
    // Parallel loading of model, tokenizer, and processor
    await Promise.all(promises);
    return result;   // { model: <PreTrainedModel>, tokenizer: <Tokenizer> }
}

```

When `cls` is a model class (e.g., `BertForSequenceClassification`), calling `cls.from_pretrained(model, pretrainedOptions)` creates a new `PreTrainedModel` instance with its own ONNX sessions. To share weights, you must bypass this automatic instantiation and provide your own model instance.

## When Weight Sharing Occurs

The library handles model reuse differently depending on how you instantiate pipelines:

- **Calling `pipeline()` twice with the same model ID**: Each call executes `loadItems()`, and `PreTrainedModel.from_pretrained` recreates ONNX sessions every time. **No sharing occurs**—each pipeline maintains separate session objects.

- **Manually constructing the model once**: Calling `await AutoModelForSequenceClassification.from_pretrained('model-id', options)` returns a `PreTrainedModel` instance that holds the sessions. Passing this same instance to pipeline constructors enables **true weight sharing** across all pipelines.

- **Sharing tokenizers and processors**: Tokenizers are lightweight JavaScript objects. Instantiate once with `await AutoTokenizer.from_pretrained()` and reuse across pipelines without memory concerns.

## Practical Implementation: Sharing a Model Across Multiple Pipelines

The following pattern demonstrates how to load a model once and share it between a sentiment analysis pipeline and a zero-shot classification pipeline:

```javascript
import {
  AutoModelForSequenceClassification,
  AutoTokenizer,
  pipeline,
} from '@huggingface/transformers';

// Configuration options for device and quantization
const sharedOptions = {
  device: 'webgpu',          // or 'cpu', 'wasm'
  dtype:  'fp16',             // matches pre-quantized model file
  cache_dir: './my_cache',
};

// 1. Load the heavy model and tokenizer once
const model = await AutoModelForSequenceClassification.from_pretrained(
  'onnx-community/gpt2-ONNX',
  sharedOptions,
);
const tokenizer = await AutoTokenizer.from_pretrained(
  'onnx-community/gpt2-ONNX',
  sharedOptions,
);

// 2. Instantiate multiple pipelines with shared references
const sentiment = new (await import('./src/pipelines/text-classification.js')).TextClassificationPipeline({
  model,
  tokenizer,
});

const zeroShot = new (await import('./src/pipelines/zero-shot-classification.js')).ZeroShotClassificationPipeline({
  model,
  tokenizer,
});

// 3. Execute inference—both pipelines use the same ONNX sessions
console.log(await sentiment('I love transformers!'));
console.log(await zeroShot('I love transformers!', {
  candidate_labels: ['positive', 'negative', 'neutral'],
}));

// 4. Clean up all sessions in one operation
await model.dispose();   // Releases memory for both pipelines

```

In this implementation, `AutoModelForSequenceClassification.from_pretrained` creates exactly one set of ONNX sessions. Both `TextClassificationPipeline` and `ZeroShotClassificationPipeline` receive references to the same `model` and `tokenizer` objects, eliminating redundant I/O and memory allocation.

## Checking Cache Status Before Loading

To check whether a model is fully cached before attempting to load it—useful for progress indicators or offline detection—use the `ModelRegistry` API:

```javascript
import { ModelRegistry } from '@huggingface/transformers';

const { allCached, files } = await ModelRegistry.is_cached(
  'onnx-community/gpt2-ONNX',
  { dtype: 'fp16' }
);

if (!allCached) {
  console.log('Downloading missing files...');
}

```

This function calls `get_files()` to enumerate required assets, then `check_files_cache()` to verify local availability.

## Key Source Files for Pipeline Management

Understanding these files helps you debug and optimize your implementation:

| File | Purpose for Weight Sharing |
|------|---------------------------|
| [`src/utils/model_registry/ModelRegistry.js`](https://github.com/huggingface/transformers.js/blob/main/src/utils/model_registry/ModelRegistry.js) | Central API for file discovery, cache checking, and cache management |
| [`src/utils/model-loader.js`](https://github.com/huggingface/transformers.js/blob/main/src/utils/model-loader.js) | Contains `constructSessions()` which builds ONNX sessions; reuse avoids rebuilding |
| [`src/pipelines.js`](https://github.com/huggingface/transformers.js/blob/main/src/pipelines.js) | Houses `loadItems()`; shows how the factory loads components that you can bypass |
| [`src/pipelines/_base.js`](https://github.com/huggingface/transformers.js/blob/main/src/pipelines/_base.js) | Defines the `Pipeline` base class with the `dispose()` method for cleanup |
| [`src/models/modeling_utils.js`](https://github.com/huggingface/transformers.js/blob/main/src/models/modeling_utils.js) | Implements `PreTrainedModel` class that holds the `sessions` map |

## Summary

- **Load once, reuse everywhere**: Instantiate `PreTrainedModel` via `AutoModel.from_pretrained()` and pass the same instance to multiple pipeline constructors.
- **Avoid the convenience trap**: The `pipeline()` factory function creates new sessions per call; manual construction is required for sharing.
- **Cleanup is centralized**: Calling `dispose()` on the shared model instance releases resources for all connected pipelines.
- **Check cache proactively**: Use `ModelRegistry.is_cached()` to verify local availability before triggering downloads.

## Frequently Asked Questions

### How do I share a model between different pipeline types in Transformers.js?

Instantiate your model once using the appropriate `AutoModel` class (such as `AutoModelForSequenceClassification.from_pretrained()`), then pass that same model instance to each pipeline constructor. For example, share a single BERT model between both `TextClassificationPipeline` and `TokenClassificationPipeline` by injecting the identical model object into both constructors rather than letting each pipeline load its own copy.

### Does calling the `pipeline()` function multiple times share weights automatically?

No. Each call to `pipeline()` invokes `loadItems()`, which triggers `PreTrainedModel.from_pretrained()` and creates new ONNX sessions. To share weights, you must manually construct the model and tokenizer first, then instantiate pipeline classes directly with those pre-loaded instances.

### What is the memory impact of sharing model weights across pipelines?

Sharing a `PreTrainedModel` instance ensures that only one copy of the ONNX sessions resides in GPU or CPU memory, regardless of how many pipelines reference it. This reduces memory consumption linearly compared to loading separate instances for each pipeline. The model's `dispose()` method then releases all shared resources in a single operation.

### Can I share only the tokenizer or processor between pipelines?

Yes. Tokenizers and processors are lightweight JavaScript objects that consume minimal memory. You can safely instantiate them once with `AutoTokenizer.from_pretrained()` or `AutoProcessor.from_pretrained()` and reuse the same instance across any number of pipelines without significant performance considerations.