Where models come from
Every loader takes a ModelSource, and there are exactly three shapes. Nothing here
guesses a host, and there is no /models/ convention baked in — if you don’t say where the
weights are, the library doesn’t invent an answer.
type ModelSource = | { hub: string } // the Hugging Face Hub, by repo id | { base: string; id: string } // a folder you serve over HTTP | { archive: ArchiveSource; zip?: ZipLike } // a portable zipThe same three work for NexusChat.load, NexusEmbedder.load, and both slots of
NexusKnowledge.create.
The Hub
Section titled “The Hub”await NexusChat.load({ hub: 'onnx-community/Qwen3-0.6B-ONNX' });Simplest for a demo or a prototype. The browser fetches weights from Hugging Face, so it needs internet and your users’ traffic goes to a third party.
Your own host
Section titled “Your own host”await NexusChat.load({ base: '/models/', id: 'Qwen/Qwen3-0.6B' });await NexusChat.load({ base: 'https://cdn.example.com/m/', id: 'Qwen/Qwen3-0.6B' });Files are expected at ${base}${id}/config.json, ${base}${id}/onnx/model_q4.onnx, and so
on — the standard Transformers.js layout. A relative base resolves against the page. This
is the production shape: your CDN, your cache headers, your uptime, no third-party
dependency at runtime.
A portable archive
Section titled “A portable archive”await NexusChat.load({ archive: fileTheUserPicked }); // File from <input>await NexusChat.load({ archive: 'https://host/model.zip' }); // URLawait NexusChat.load({ archive: bytes }); // Blob / Uint8ArrayThe archive is restored into the browser cache first, then the model loads out of that cache — so loading needs no further network at all. This is the air-gap path, and the one that makes a knowledge base shippable on a USB stick. See offline bundles.
Make one with exportModel:
import { exportModel } from 'browser-llm-nexus/model';
const zip = await exportModel('Qwen/Qwen3-0.6B', { modelsUrl: 'https://cdn.example.com/m/', dtypes: ['q4'], // ship one variant — keeps it small enough to hand someone});Anything serving the standard layout works
Section titled “Anything serving the standard layout works”Hugging Face, your static host, a build step of your own — if it serves the Transformers.js
file layout, it’s a valid base. Converting a PyTorch model into that layout is a separate
job, and nothing here depends on any particular tool doing it.
Getting a model into that layout: hf2browser
Section titled “Getting a model into that layout: hf2browser”Most models on the Hub ship PyTorch weights, not ONNX. hf2browser is an open-source converter that turns one into the layout above. It is a sister project, not a dependency — this library never calls it and never needs to.
hf2browser check Qwen/Qwen3-0.6B # tool-calling support, size, taskhf2browser convert Qwen/Qwen3-0.6B --modes q4,q8,fp16hf2browser serve # http://localhost:8917Serve it, or hand it over as a file
Section titled “Serve it, or hand it over as a file”hf2browser serve gives you both source kinds at once:
// Served — a plain base URL, streamed and cached like any other host.await NexusChat.load({ base: 'http://localhost:8917/models/', id: 'Qwen/Qwen3-0.6B' });
// Packed — one zip, no server, works offline and off a USB stick.await NexusChat.load({ archive: 'http://localhost:8917/api/model.zip?model=Qwen/Qwen3-0.6B&dtype=q4' });That /api/model.zip endpoint emits exactly the manifest.json + files/N.bin layout
importModel() reads — same kind / modelId /
createdAt / dtypes / files[{file,url,path}] shape this library’s own exportModel()
writes. Drop the download straight into a <input type="file"> and { archive: file }
loads it, with no conversion step in between:
input.onchange = () => NexusChat.load({ archive: input.files[0] });Omit &dtype= to pack every variant the conversion produced and let the runtime probe.
Injecting the runtime
Section titled “Injecting the runtime”Transformers.js itself is an injectable peer dependency. Pass your own build — a pinned version, a lite build, a patched fork — and the library uses it instead of loading one from a CDN:
import * as transformers from '@huggingface/transformers';
const chat = await NexusChat.load(source, { transformers });fflate is injectable the same way via { zip } on any archive call.
Related
Section titled “Related”- GPU or CPU — which dtype gets picked out of what your source serves
- Knowledge & offline bundles — archives, composed