MLContext
Experimental: This is an experimental technology. Check the browser compatibility table carefully before using it in production.
The MLContext interface of the Web Neural Network (WebNN) API represents the global state of neural network compute workloads and their execution. It owns the resources used to compile and run MLGraph objects, creates and reads/writes MLTensor objects, and reports implementation-specific operator support.
An MLContext is created with ML.createContext(). Each context has a context type:
| Context type | Created by | Description |
|---|---|---|
"default" | createContext(options) | The user agent selects the compute device according to the MLContextOptions hints. |
"webgpu" | createContext(gpuDevice) | The context is created from a WebGPU GPUDevice. |
All work that touches tensor data — graph execution, tensor writes and reads — is queued in order on the context’s timeline, so calls such as writeTensor(), dispatch() and readTensor() can be issued back-to-back without awaiting each one.
This feature is available only in secure contexts (HTTPS or localhost), and is available in both the main thread and Web Workers .
Web IDL
typedef record<USVString, MLTensor> MLNamedTensors;
dictionary MLContextLostInfo {
DOMString message;
};
[SecureContext, Exposed=(Window, Worker)]
interface MLContext {
undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs);
Promise<MLTensor> createTensor(MLTensorDescriptor descriptor);
Promise<MLTensor> createExportableTensor(
MLTensorDescriptor descriptor, GPUDevice gpuDevice);
Promise<MLTensor> createConstantTensor(
MLOperandDescriptor descriptor, AllowSharedBufferSource inputData);
Promise<ArrayBuffer> readTensor(MLTensor tensor);
Promise<undefined> readTensor(MLTensor tensor, AllowSharedBufferSource outputData);
undefined writeTensor(MLTensor tensor, AllowSharedBufferSource inputData);
GPUBuffer exportToGPU(MLTensor tensor);
MLOpSupportLimits opSupportLimits();
undefined destroy();
readonly attribute boolean accelerated;
readonly attribute Promise<MLContextLostInfo> lost;
};Instance properties
accelerated
A read-only boolean indicating whether the context uses massively parallel acceleration (such as a GPU or NPU) rather than CPU-only processing. It reflects the accelerated option the context was created with (true by default, and always true for "webgpu" contexts).
const context = await navigator.ml.createContext({ powerPreference: 'low-power' });
if (!context.accelerated) {
console.log('Running on CPU; consider a smaller model.');
}lost
A read-only Promise that fulfills with an MLContextLostInfo object when the context is lost, i.e. when its underlying execution device is no longer available or destroy() is called. The promise never rejects.
When a context is lost, every MLGraph and MLTensor created from it is destroyed, pending operations fail, and new operations on it are rejected with an InvalidStateError. To recover, create a new context and rebuild your graphs.
context.lost.then((info) => {
console.warn('MLContext lost:', info.message);
// Recreate the context, rebuild graphs, and reallocate tensors here.
});Instance methods
| Method | Description |
|---|---|
dispatch() | Schedules execution of a compiled graph with the given input and output tensors. |
createTensor() | Creates an MLTensor whose contents are initialized to zero. |
createExportableTensor() | Creates an MLTensor that can be exported to a WebGPU GPUDevice. |
createConstantTensor() | Creates an immutable constant MLTensor initialized with the given data. |
readTensor() | Reads the contents of a tensor back to script. |
writeTensor() | Writes data into a tensor. |
exportToGPU() | Exports a tensor to its associated GPUDevice as a GPUBuffer. |
opSupportLimits() | Returns the data types and ranks supported by this context for each operator. |
destroy() | Releases all resources associated with the context. |
dispatch()
The dispatch() method schedules the computational workload of a compiled MLGraph on the context’s timeline.
dispatch() returns immediately and provides no signal that execution has completed. To get results, call readTensor() on an output tensor and await it; reads are ordered after previously dispatched work.
Syntax
dispatch(graph, inputs, outputs)Parameters
-
graphThe
MLGraphto execute. It must have been built from a builder associated with this context. -
inputsAn object (
MLNamedTensors) mapping each graph input name to anMLTensor. It must contain exactly one tensor per graph input, and each tensor’sdataTypeandshapemust match the corresponding input operand. -
outputsAn object (
MLNamedTensors) mapping each graph output name to anMLTensorthat receives the result. It must contain exactly one tensor per graph output, with matchingdataTypeandshape.
Return value
None (undefined).
Exceptions
-
TypeErrorThrown if the graph or any tensor belongs to a different context; if a tensor has been destroyed, is currently exported, or is a constant tensor; if the same tensor appears more than once across
inputsandoutputs; or if the named tensors do not exactly match the graph’s inputs or outputs. -
InvalidStateErrorDOMExceptionThrown if the graph has been destroyed.
createTensor()
The createTensor() method creates an MLTensor associated with this context. All bytes of the new tensor are initialized to zero.
Syntax
createTensor(descriptor)Parameters
-
descriptorAn
MLTensorDescriptorspecifying the tensor’sdataTypeandshape, and whether it isreadableand/orwritablefrom script.
Return value
A Promise that fulfills with a new MLTensor.
Exceptions
The returned promise is rejected with:
-
InvalidStateErrorDOMExceptionThe context is lost, or was lost before the tensor was allocated.
-
UnknownErrorDOMExceptionThe tensor memory could not be allocated.
createExportableTensor()
The createExportableTensor() method creates an MLTensor that may later be exported to the given WebGPU GPUDevice with exportToGPU(). Its contents are initialized to zero.
Whether a context supports exporting to a particular GPUDevice is implementation-defined and may depend on the context type and platform.
Syntax
createExportableTensor(descriptor, gpuDevice)Parameters
-
descriptor -
gpuDeviceThe
GPUDeviceto which the tensor may be exported.
Return value
A Promise that fulfills with a new exportable MLTensor.
Exceptions
The returned promise is rejected with:
-
InvalidStateErrorDOMExceptionThe context is lost, or
gpuDeviceis lost. -
NotSupportedErrorDOMExceptionThe context cannot export tensors to
gpuDevice. -
UnknownErrorDOMExceptionThe tensor memory could not be allocated.
createConstantTensor()
The createConstantTensor() method creates a constant MLTensor initialized with a copy of inputData. A constant tensor’s constant property is true; it is neither readable nor writable, and cannot be bound as a dispatch() input or output.
Constant tensors are intended to be passed to MLGraphBuilder.constant(tensor), so that large weights are uploaded to the device once and can be shared by several graphs. It is legal to destroy a constant tensor once the graphs that use it have been built.
Syntax
createConstantTensor(descriptor, inputData)Parameters
-
descriptorAn
MLOperandDescriptorspecifying thedataTypeandshape. -
inputDataAn
ArrayBuffer,SharedArrayBuffer, orArrayBufferViewwhose bytes are copied into the tensor. See Buffer requirements.
Return value
A Promise that fulfills with a new constant MLTensor.
Exceptions
The returned promise is rejected with:
-
TypeErrorThe descriptor has an invalid shape, or
inputDatadoes not satisfy the buffer requirements. -
InvalidStateErrorDOMExceptionThe context is lost.
-
UnknownErrorDOMExceptionThe tensor could not be allocated or initialized.
readTensor()
The readTensor() method reads the contents of an MLTensor from the context’s timeline back to script. The read happens after all previously queued work on the context, so awaiting it is the way to wait for a dispatch() to finish.
There are two overloads: one that allocates and returns a new ArrayBuffer, and a bring-your-own-buffer (BYOB) variant that writes into a buffer you provide.
Syntax
readTensor(tensor)
readTensor(tensor, outputData)Parameters
-
tensorThe
MLTensorto read. It must have been created withreadable: true. -
outputDataoptionalAn
ArrayBuffer,SharedArrayBuffer, orArrayBufferViewthat receives the data. See Buffer requirements.
Return value
readTensor(tensor): aPromisethat fulfills with a newArrayBuffercontaining a copy of the tensor data.readTensor(tensor, outputData): aPromisethat fulfills withundefinedonce the data has been written intooutputData.
Exceptions
The returned promise is rejected with:
-
TypeErrorThe tensor belongs to a different context, has been destroyed, is not
readable, or is currently exported; oroutputDatadoes not satisfy the buffer requirements or was detached before the read completed. -
InvalidStateErrorDOMExceptionThe context was lost, or the tensor was destroyed while the read was pending.
-
UnknownErrorDOMExceptionThe data could not be read.
writeTensor()
The writeTensor() method copies the bytes of inputData into an MLTensor on the context’s timeline. The data is copied synchronously when the method is called, so inputData can be reused or modified immediately afterwards.
Like dispatch(), writeTensor() gives no signal when the write has completed; subsequent dispatch() and readTensor() calls are ordered after it.
Syntax
writeTensor(tensor, inputData)Parameters
-
tensorThe
MLTensorto write to. It must have been created withwritable: true. -
inputDataAn
ArrayBuffer,SharedArrayBuffer, orArrayBufferViewcontaining the data. See Buffer requirements.
Return value
None (undefined).
Exceptions
-
TypeErrorThrown if the tensor belongs to a different context, has been destroyed, is not
writable, or is currently exported, or ifinputDatadoes not satisfy the buffer requirements.
exportToGPU()
The exportToGPU() method exports an exportable MLTensor (created with createExportableTensor()) to its associated GPUDevice and returns a GPUBuffer that WebGPU commands can use.
While a tensor is exported, the GPUDevice has exclusive access to its contents, and dispatch(), readTensor() and writeTensor() calls that use it throw (or reject with) a TypeError. Calling GPUBuffer.destroy() on the returned buffer returns the tensor to WebNN, after which it can be used again.
- The returned buffer has a
sizeequal to the tensor’s byte length and ausageofGPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST. - Calling
exportToGPU()again on a tensor that is already exported returns the sameGPUBuffer. - The user agent orders the transfer correctly: WebGPU work submitted using the buffer runs after pending WebNN work on the tensor, and WebNN work after
destroy()runs after pending WebGPU work on the buffer. No manual synchronization is required. - Exporting is not guaranteed to be zero-copy; the contents may be copied to and from GPU memory.
- Destroying the tensor or its context while exported does not invalidate the
GPUBuffer. If theGPUDeviceis lost, the tensor stays exported untilGPUBuffer.destroy()is called.
Syntax
exportToGPU(tensor)Parameters
-
tensorAn exportable
MLTensorcreated by this context.
Return value
A GPUBuffer associated with the tensor’s GPUDevice.
Exceptions
-
TypeErrorThrown if the tensor belongs to a different context, has been destroyed, or was not created with
createExportableTensor(). -
InvalidStateErrorDOMExceptionThrown if the tensor’s
GPUDeviceis lost.
opSupportLimits()
The opSupportLimits() method returns an MLOpSupportLimits dictionary describing which data types and tensor ranks this context supports, both globally and for each operator. Use it to choose a model variant (for example float16 vs. float32, or "nchw" vs. "nhwc") that runs best on the current platform.
Every implementation supports at least the required data types and ranks listed for each operator in MLGraphBuilder operations, and may support more.
opSupportLimits()is not intended to add fingerprinting entropy; in current implementations the same information can be inferred from the OS and browser version.
Syntax
opSupportLimits()Parameters
None.
Return value
An MLOpSupportLimits dictionary.
destroy()
The destroy() method releases all resources associated with the context. It loses the context: the lost promise fulfills with an implementation-defined message, and all graphs and tensors created from the context are destroyed. Outstanding compute requests and tensor creation, read, and write requests fail. Calling destroy() on a context that is already lost does nothing.
Syntax
destroy()Return value
None (undefined).
Buffer requirements
createConstantTensor(), readTensor(tensor, outputData) and writeTensor() (as well as MLGraphBuilder.constant()) validate the buffer against the tensor descriptor:
- The buffer’s byte length must equal the descriptor’s byte length (number of elements × element size).
- An
ArrayBufferorSharedArrayBufferis always accepted. - An
ArrayBufferViewis accepted if it is aUint8Array(a generic byte view, e.g. a slice of aWebAssembly.Memory), or if its type matches the data type:
MLOperandDataType | Matching ArrayBufferView | Element size |
|---|---|---|
"float32" | Float32Array | 4 bytes |
"float16" | Float16Array | 2 bytes |
"int64" | BigInt64Array | 8 bytes |
"uint64" | BigUint64Array | 8 bytes |
"int32" | Int32Array | 4 bytes |
"uint32" | Uint32Array | 4 bytes |
"int8" | Int8Array | 1 byte |
"uint8" | Uint8Array | 1 byte |
Where
Float16Arrayis not available yet, pass the raw IEEE 754 half-precision bits through aUint16Array’s underlyingArrayBuffer(or aUint8Arrayview).
Dictionaries
MLContextLostInfo
The value that the lost promise fulfills with.
| Member | Type | Description |
|---|---|---|
message | DOMString | An implementation-defined message describing why the context was lost. |
MLOpSupportLimits
Returned by opSupportLimits(). Besides the top-level members below, it has one member per operator, named after the MLGraphBuilder method (for example conv2d, add, softmax), whose value describes the limits for that operator’s operands.
dictionary MLOpSupportLimits {
MLInputOperandLayout preferredInputLayout;
[EnforceRange] unsigned long long maxTensorByteLength;
MLTensorLimits input;
MLTensorLimits constant;
MLTensorLimits output;
// ...plus one member per operator, e.g.:
// MLConv2dSupportLimits conv2d;
// MLBinarySupportLimits add;
// MLSingleInputSupportLimits softmax;
};| Member | Type | Description |
|---|---|---|
preferredInputLayout | MLInputOperandLayout | The preferred input layout ("nchw" or "nhwc") for layout-dependent operators such as conv2d(). |
maxTensorByteLength | unsigned long long | The maximum supported tensor size, in bytes. |
input | MLTensorLimits | Limits for graph input operands. |
constant | MLTensorLimits | Limits for graph constant operands. |
output | MLTensorLimits | Limits for graph output operands. |
| operator name | operator-specific dictionary | Limits for each operand of that operator, for example MLSingleInputSupportLimits or MLBinarySupportLimits. See each operator in MLGraphBuilder operations. |
MLTensorLimits
typedef sequence<MLOperandDataType> MLDataTypeList;
dictionary MLTensorLimits {
MLDataTypeList dataTypes;
MLRankRange rankRange;
};| Member | Type | Description |
|---|---|---|
dataTypes | sequence<MLOperandDataType> | The supported data types. |
rankRange | MLRankRange | The minimum and maximum supported ranks. |
MLRankRange
dictionary MLRankRange {
unsigned long min;
unsigned long max;
};| Member | Type | Description |
|---|---|---|
min | unsigned long | The minimum supported rank. |
max | unsigned long | The maximum supported rank. |
MLSingleInputSupportLimits
Used by operators with one tensor input, such as relu(), softmax() or reshape().
dictionary MLSingleInputSupportLimits {
MLTensorLimits input;
MLTensorLimits output;
};MLBinarySupportLimits
Used by operators with two tensor inputs a and b, such as add(), equal() or matmul().
dictionary MLBinarySupportLimits {
MLTensorLimits a;
MLTensorLimits b;
MLTensorLimits output;
};Other operators use dedicated dictionaries with one MLTensorLimits member per operand — for example MLConv2dSupportLimits has input, filter, bias and output. They are listed with each operator in MLGraphBuilder operations.
Examples
Executing a graph with MLTensors
const descriptor = { dataType: 'float32', shape: [2, 2] };
const context = await navigator.ml.createContext();
const builder = new MLGraphBuilder(context);
// 1. Create a computational graph 'C = 0.2 * A + B'.
const constant = builder.constant(descriptor, new Float32Array(4).fill(0.2));
const A = builder.input('A', descriptor);
const B = builder.input('B', descriptor);
const C = builder.add(builder.mul(A, constant), B);
// 2. Compile the graph.
const graph = await builder.build({ C });
// 3. Create reusable input and output tensors.
const [inputTensorA, inputTensorB, outputTensorC] = await Promise.all([
context.createTensor({ dataType: A.dataType, shape: A.shape, writable: true }),
context.createTensor({ dataType: B.dataType, shape: B.shape, writable: true }),
context.createTensor({ dataType: C.dataType, shape: C.shape, readable: true }),
]);
// 4. Initialize the inputs.
context.writeTensor(inputTensorA, new Float32Array(4).fill(1.0));
context.writeTensor(inputTensorB, new Float32Array(4).fill(0.8));
// 5. Execute the graph.
context.dispatch(graph, { A: inputTensorA, B: inputTensorB }, { C: outputTensorC });
// 6. Read back the computed result.
const result = await context.readTensor(outputTensorC);
console.log('Output value:', new Float32Array(result)); // [1, 1, 1, 1]Reading into an existing buffer
Reusing an output buffer avoids allocating a new ArrayBuffer for every inference:
const output = new Float32Array(4);
for (const frame of frames) {
context.writeTensor(inputTensor, frame);
context.dispatch(graph, { input: inputTensor }, { output: outputTensor });
await context.readTensor(outputTensor, output);
render(output);
}Sharing weights with a constant tensor
const weightDesc = { dataType: 'float32', shape: [4, 4] };
const weights = await context.createConstantTensor(weightDesc, new Float32Array(16).fill(0.5));
console.log(weights.constant); // true
async function buildGraph() {
const builder = new MLGraphBuilder(context);
const x = builder.input('x', { dataType: 'float32', shape: [1, 4] });
return builder.build({ y: builder.matmul(x, builder.constant(weights)) });
}
// Both graphs reuse the same device-side weights.
const [graphA, graphB] = await Promise.all([buildGraph(), buildGraph()]);
weights.destroy(); // Safe once the graphs are built.Checking operator support limits
const context = await navigator.ml.createContext();
const limits = context.opSupportLimits();
console.log('Preferred layout:', limits.preferredInputLayout); // "nchw" or "nhwc"
console.log('Max tensor size:', limits.maxTensorByteLength, 'bytes');
// Pick a float16 model if conv2d supports float16 inputs on this context.
const useFp16 = limits.conv2d.input.dataTypes.includes('float16');
const modelUrl = useFp16 ? 'model-fp16.onnx' : 'model-fp32.onnx';
// Check whether gather() accepts int64 indices.
const supportsInt64Indices = limits.gather.indices.dataTypes.includes('int64');
// Check the maximum rank supported by add().
console.log('add() max rank:', limits.add.a.rankRange.max);Interoperating with WebGPU
// 1. Create WebGPU and WebNN contexts.
const gpuAdapter = await navigator.gpu.requestAdapter();
const gpuDevice = await gpuAdapter.requestDevice();
const context = await navigator.ml.createContext();
// 2. Build a simple graph: y = x + 1.
const builder = new MLGraphBuilder(context);
const descriptor = { dataType: 'float32', shape: [4] };
const x = builder.input('x', descriptor);
const one = builder.constant(descriptor, new Float32Array([1, 1, 1, 1]));
const graph = await builder.build({ y: builder.add(x, one) });
// 3. Create exportable tensors and run WebNN dispatch.
const inputTensor = await context.createExportableTensor(
{ ...descriptor, writable: true }, gpuDevice);
const outputTensor = await context.createExportableTensor(
{ ...descriptor, readable: true }, gpuDevice);
context.writeTensor(inputTensor, new Float32Array([1, 2, 3, 4]));
context.dispatch(graph, { x: inputTensor }, { y: outputTensor });
// 4. Export to WebGPU and use the buffer in GPU commands.
const gpuBuffer = context.exportToGPU(outputTensor);
// ... use gpuBuffer in WebGPU compute or render passes ...
// 5. Return the tensor to WebNN, then read it from WebNN again.
gpuBuffer.destroy();
const result = new Float32Array(await context.readTensor(outputTensor));
console.log(result); // [2, 3, 4, 5]Specifications
| Specification | Status |
|---|---|
Web Neural Network API — MLContext interface | Candidate Recommendation Draft |
The latest Editor’s Draft is available at webmachinelearning.github.io/webnn .
Browser compatibility
WebNN is under active development and support varies across browsers, operating systems, and hardware.
createExportableTensor()andexportToGPU()are recent additions and may not be implemented yet.
See Browser Compatibility: WebNN APIs.