Quickstart
These docs describe bgcut 0.6.1.
Run the local web app from npm without installing bgcut globally:
npx bgcutChoose an interface
Web UI
Choose, drag, or paste an image. bgcut removes the background in the browser. Use the comparison slider to inspect the result, then copy or download the PNG, rerun the removal, or choose another image. The browser accepts JPEG, PNG, WebP, and AVIF.
Automatic browser mode tries ONNX Runtime WebGPU first. If WebGPU is unavailable or its setup or inference fails, bgcut retries with ONNX Runtime WebAssembly. Both paths run inference on the user's device.
Local app
Run bgcut with no image to start the packaged remover on 127.0.0.1. The local UI contains the bgcut brand and removal workflow only. Docs, Changelog, GitHub navigation, Privacy, Terms, and the site footer remain on bgcut.dev.
npm install -g bgcut
bgcut
# explicit form
bgcut serve
# fixed port
bgcut serve --port 8787
# keep the browser closed
bgcut serve --no-open
# machine-readable startup metadata
bgcut serve --jsonserve --json does not open a browser. It prints one JSON object withurl, host, port, and pid. If --port is omitted, the operating system chooses an available port. Non-root app routes redirect to /. The server exposes/health, the validated model under /models/..., and the installed ONNX Runtime browser files under /runtime/.... Image inference still runs in the browser.
CLI
Pass one image path for the existing file-in/file-out flow. Pass several files or a directory for batch removal. Directory scans are recursive. Batch inference runs one image at a time and reuses one warm runtime.
bgcut photo.jpg
bgcut remove photo.jpg
bgcut photo.jpg -o portrait.png
# several files or a directory
bgcut first.jpg second.png
bgcut photos/
bgcut photos/ -o ./cutouts
# output formats
bgcut photo.jpg --png
bgcut photo.jpg --webp
bgcut photo.jpg --jpg
# provider constraints
bgcut photo.jpg --gpu
bgcut photo.jpg --cpu--gpu returns an error if the WebGPU runtime cannot startFor a single file, --output names the output file. For a batch, it names an output directory and preserves nested paths. Without --output, each result is written next to its source image. Sharp/libvips decodes each image from its contents, not from the filename extension. bgcut also accepts -png, -webp, -jpg,-gpu, and -cpu.
Node API
Install bgcut from npm:
npm install bgcutOpen bgcut
import { bgcut } from "bgcut";
const remover = await bgcut();
try {
// Use remover.removeBackground() or remover.removeMany().
} finally {
await remover.close();
}Migrating from 0.5.x to 0.6.1
bgcut 0.6.1 does not export the old top-level removeBackground() orcreateBgcut() functions. Open one instance with bgcut(), call methods on that instance, and close it when finished. Choose the engine when opening the instance. Choose the output format per removal.
One image in 0.5.x:
import { removeBackground } from "bgcut";
const result = await removeBackground("photo.jpg", {
engine: "cpu",
format: "webp",
});The same call in 0.6.1:
import { bgcut } from "bgcut";
const remover = await bgcut({ engine: "cpu" });
try {
const result = await remover.removeBackground("photo.jpg", {
format: "webp",
});
} finally {
await remover.close();
}Reusable work in 0.5.x:
import { createBgcut } from "bgcut";
const remover = await createBgcut();
try {
await remover.remove("first.jpg");
await remover.remove("second.jpg");
} finally {
await remover.close();
}The same work in 0.6.1:
import { bgcut } from "bgcut";
const remover = await bgcut();
try {
await remover.removeBackground("first.jpg");
await remover.removeBackground("second.jpg");
} finally {
await remover.close();
}For several inputs, prefer removeMany(). It accepts files, directories, iterables, and async iterables. It yields each result as it finishes and keeps later inputs running after an image-level failure.
Single image
Use removeBackground() on the bgcut instance. Choose the output format per image when needed.
const result = await remover.removeBackground("photo.jpg");
const webp = await remover.removeBackground("photo.jpg", {
format: "webp",
});Multiple images
Use removeMany() for several files, a directory, an iterable, or an async iterable. Results are yielded one at a time. Processing is sequential so one warm runtime can be reused without decoding an entire batch up front.
for await (const item of remover.removeMany([
"first.jpg",
"second.png",
])) {
if (!item.ok) {
console.error(item.source.input, item.error);
continue;
}
console.log(item.source.input, item.result);
}Directory inputs are recursive by default. Pass recursive: false to process only the immediate image files.
for await (const item of remover.removeMany("photos", {
recursive: false,
})) {
// ...
}Inputs and result
Single-image inputs can be a file path, Uint8Array, orArrayBuffer. removeMany() accepts one of those inputs or an iterable/async iterable of them. Supported image formats are JPEG, PNG, WebP, and AVIF.
type BgcutRemovalResult = {
data: Uint8Array;
width: number;
height: number;
format: "png" | "webp" | "jpg";
engine: "webgpu" | "cpu";
fallbackReason: string | undefined;
timings: {
totalMs: number;
prepareMs: number;
inferenceMs: number;
encodeMs: number;
};
};Engines and lifecycle
Choose the engine when opening bgcut. bgcut({ engine: "gpu" })requires native WebGPU, while bgcut({ engine: "cpu" }) requires CPU. The default auto mode tries WebGPU first and falls back to CPU if runtime creation fails. Always call close() when finished.
Errors
Node API failures use one public error type. Handle BgcutError.codeinstead of depending on Effect or ONNX Runtime error classes.
import { BgcutError, bgcut } from "bgcut";
const remover = await bgcut();
try {
await remover.removeBackground("photo.jpg");
} catch (error) {
if (error instanceof BgcutError) {
console.error(error.code, error.message);
}
} finally {
await remover.close();
}Error codes are model, engine, input,inference, output, and closed.
Model and runtime
The model input is 512 x 512. bgcut restores the matte to the source image size before export.
bgcut uses studioludens/birefnet-lite-512 at one pinned source revision. The runtime has validated FP32 and internal-FP16 artifacts with the same 512 x 512 public model input.
4a3c40c36c94093cc1e724d9ea428b8fa4b57dc7| Artifact | Runtime | Size | SHA-256 |
|---|---|---|---|
FP32birefnet-lite-512-ort-basic-webgpu-v2.onnx | Native CLI, Node API, Chromium WebGPU, browser WebAssembly, Safari fallback | 195,872,736 bytes | 4461109672dda07a054892aef076b5fcc5fc40bbc91f51a357a7593c7f45ad9c |
FP16birefnet-lite-512-ort-basic-webgpu-v2-fp16.onnx | Safari WebGPU with shader-f16 | 98,572,669 bytes | 37d4035765b97a0323729fdee787d16eb7238c39c467316e887c5292792f3e33 |
The npm package does not include either model artifact. Native CLI and Node API runs use FP32. The packaged local browser app can cache both artifacts in the operating-system user cache. Safari WebGPU uses FP16 only when the device exposes shader-f16; Safari without that feature, Chromium-family WebGPU, and browser WebAssembly use FP32. bgcut verifies the byte size and SHA-256 before reusing a cached model.
Architecture
Browser and native paths use a 512 x 512 model input and composite the matte at the source image size.
Cloudflare Workers hosts bgcut.dev. Workers Static Assets serves the app files. Private R2 stores both pinned model artifacts and the ONNX Runtime browser files. The Worker exposes them through same-origin /models/* and /runtime/* routes.
Resources
Humans can use the docs and type declarations directly. Agents can start with the plain-text index or the packaged skill.