# opencv-js: the OpenCV wasm build packaged for Node and the browser

> This package ships the official OpenCV.js build as an npm module, with TypeScript declarations and a CLI tool that reformats help output from other packages. The interesting part is the loading dance, because the module resolves differently depending on whether the wasm is already instantiated.

**TechStark/opencv-js** — OpenCV JavaScript version for node.js or browser

- Repository: https://github.com/TechStark/opencv-js
- Website: https://npmjs.com/@techstark/opencv-js
- Stars: 786 · Forks: 58
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/techstark-opencv-js

## It is the official wasm build, packaged

opencv-js is the OpenCV JavaScript version for node.js or browser, and the repository makes its provenance explicit: the file opencv.js was downloaded from the OpenCV documentation site for version 5.0.0. That matters for how you evaluate it. This is not a reimplementation of OpenCV in JavaScript, it is the Emscripten build of the C++ library with TypeScript declarations and npm packaging around it. The consequences follow from that. You inherit the upstream build's size and its start-up behaviour, you inherit whatever subset of the OpenCV API the upstream build exposes, and you inherit its version cadence, which is the OpenCV.js build numbering rather than the C++ library's. The package is published as @techstark/opencv-js, with the main entry at dist/opencv.js and the type declarations at src/index.d.ts, and the published files are dist/ and src/.

## The loading dance handles three shapes of the same module

The basic usage example is really a load-time negotiation, and it is the part of this package you will copy verbatim. You import the default export, then check what you actually got. If the module is a Promise you await it. If it is not a Promise but already has a Mat property, the wasm is instantiated and you use it directly. Otherwise you assign an onRuntimeInitialized callback that resolves a promise, and the module is instantiated as a side effect of the assignment. Only after one of those three paths do you have a usable cv:

```js
import cvModule from "@techstark/opencv-js";

async function getOpenCv() {
  let cv;
  if (cvModule instanceof Promise) {
    cv = await cvModule;
  } else {
    if (cvModule.Mat) {
      cv = cvModule;
    } else {
      await new Promise((resolve) => {
        cvModule.onRuntimeInitialized = () => resolve();
      });
      cv = cvModule;
    }
  }
  return { cv };
}
```

The reason there are three paths is that the module format varies with the bundler and the runtime, and the check for a Mat property is the cheapest reliable signal that the wasm is ready. That detection is what people copy from the README, and it is also what people get wrong when they skip it, because calling into cv before it is ready fails in a way that looks like a missing function.

## Installing is one package, and the import style is your choice

The How to Use section gives the options plainly. The package installs with npm install @techstark/opencv-js or yarn add @techstark/opencv-js. Then you either import the default export, import cv from "@techstark/opencv-js", in which case for TypeScript you need to set "esModuleInterop": true in your tsconfig.json, or you import the namespace, import * as cv from "@techstark/opencv-js". TypeScript is supported, thanks to the mirada project according to the README. The two import styles are not interchangeable in every setup, and the esModuleInterop requirement is the one detail that catches people out when they follow the default import path in a strict TypeScript project.

## Browser use needs three webpack fallbacks

If you use this package for browsers, you need to set some polyfills in your webpack.config.js, and the fix is small enough to quote in full:

```js
module.exports = {
  resolve: {
    modules: [...],
    fallback: {
      fs: false,
      path: false,
      crypto: false
    }
  }
};
```

The three modules are Node built-ins that the Emscripten build references but a browser does not have, and setting them to false tells webpack not to try to polyfill them. This is a symptom of the packaging approach rather than of the project. Because the same file has to serve Node and the browser, the Node-only paths are still present in the bundle, and the browser build has to be told to ignore them. The README documents the webpack case; if you are on another bundler, you will need to work out the equivalent yourself, which is the sort of small piece of friction that a package built for the browser from the start would not have.

## The type declarations lag, and there is a file that tells you the truth

The one caveat the README states is worth quoting in substance: the TypeScript type declarations may not be up to date with the latest OpenCV.js, and you are referred to doc/cvKeys.json to check the available methods and properties at runtime. That is an honest limitation of wrapping a generated C++ API. OpenCV has thousands of symbols, and the declaration file in src/ has to be maintained by hand against a build that changes shape. The cvKeys.json file in the doc/ directory is the generated inventory of what the runtime actually exposes, so the workflow when a method appears missing is to check that file rather than to assume the API is not there. The repository has a jest.config.js, a tsconfig.test.json and a test directory, and a separate test:compat script that runs node test/compat/run-all.mjs, which is the shape you would expect for checking the wrapper against several upstream builds.

## Releases ship as numbered builds, not a final tag

The release history explains the versioning. The most recent artefacts are opencv-js-5.0.0-build9 on 2026-06-26, opencv-js-5.0.0-build8 the same day, and opencv-js-5.0.0-build6 on 2026-06-25, and the package version in the manifest is 5.0.0-release.1. So during the 5.0.0 line the npm releases are numbered builds of the upstream OpenCV.js release rather than a single final tag, and the manifest has moved on to a release candidate suffix. The practical instruction is to install the exact build you tested rather than a floating latest, because the API surface can change between builds and the type declarations may not track it. The licence is Apache-2.0 with the LICENSE file at the root, the repository is not archived and the last push was on 2026-08-01.

## Conclusion

Adopt opencv-js if you want computer vision in JavaScript without running a Python service, and you can live with the constraints of the upstream OpenCV.js build. Do not adopt it expecting the type declarations to be complete, because the README says they may not be up to date with the latest OpenCV.js and points you at doc/cvKeys.json for the runtime truth. Before you commit, check the release tags you are installing, since the 5.0.0 line ships as numbered builds rather than a single final release, and decide between the default import and the namespace import based on how your bundler handles the module.

## FAQ

### What is opencv-js?

It is an Apache-2.0 licensed npm package providing the OpenCV JavaScript version for node.js or the browser, built by taking the official opencv.js file from the OpenCV documentation site for version 5.0.0 and packaging it with TypeScript declarations. The package is published as @techstark/opencv-js.

### How do I install and import opencv-js?

Run npm install @techstark/opencv-js or yarn add @techstark/opencv-js, then either import the default export, which for TypeScript needs "esModuleInterop": true in tsconfig.json, or import the namespace with import * as cv. The module may resolve as a promise, as an already instantiated object with a Mat property, or need an onRuntimeInitialized callback.

### What do I need to configure to use opencv-js in a browser?

With webpack you need to set resolve.fallback for fs, path and crypto to false, because the Emscripten build references Node built-ins that a browser does not have. The README documents the webpack case specifically.

### Are the opencv-js TypeScript definitions up to date?

Not always. The README states that the type declarations may not be up to date with the latest OpenCV.js, and points to doc/cvKeys.json to check the available methods and properties at runtime. The releases during the 5.0.0 line are numbered builds, so the newest tag is opencv-js-5.0.0-build9 from 2026-06-26.

## Sources

- [License: Apache-2.0](https://github.com/TechStark/opencv-js/blob/main/LICENSE)
- [Project website](https://npmjs.com/@techstark/opencv-js)
- [README](https://github.com/TechStark/opencv-js/blob/main/README.md)
- [Releases](https://github.com/TechStark/opencv-js/releases)
- [TechStark/opencv-js on GitHub](https://github.com/TechStark/opencv-js)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/techstark-opencv-js
