High-performance OpenStreetMap tools for TypeScript and JavaScript environments.
Osmix is a collection of composable libraries for reading, querying, merging, and transforming OpenStreetMap PBF data in browsers and Node.js. Built on streaming APIs and Web Workers, Osmix handles large extracts efficiently with spatial indexing, vector tile generation, and in-browser merge workflows.
Key Features:
- Streaming PBF parsing with minimal memory overhead
- Spatial queries via R-tree indexes (KDBush, Flatbush)
- Merge and deduplicate OSM extracts
- Cross-platform – ESM-native, runs in Node.js, Bun, Deno, and browsers
- Generate raster and vector tiles
- Worker-based processing for responsive UIs
Try it: merge.osmix.dev · Docs & examples: osmix.dev
pnpm add osmiximport { fromPbf, toPbfBuffer, transformOsmPbfToJson, merge, isNode } from "osmix";
// Load a PBF file
const monacoResponse = await fetch("./monaco.pbf");
const monacoPbf = new Uint8Array(await monacoResponse.arrayBuffer());
const osm = await fromPbf(monacoPbf);
// Query entities by ID
const node = osm.nodes.getById(123456);
const way = osm.ways.getById(789012);
const relation = osm.relations.getById(345678);
console.log(node, way, relation);
// Spatial queries with bounding box
const bbox: [number, number, number, number] = [7.41, 43.72, 7.43, 43.74];
const nodeResults = osm.nodes.withinBbox(bbox);
const wayResults = osm.ways.withinBbox(bbox);
console.log(`Found ${nodeResults.ids.length} nodes and ${wayResults.ids.length} ways`);
// Stream parse a PBF into JSON entities
const stream = transformOsmPbfToJson(monacoPbf.buffer);
for await (const entity of stream) {
if ("id" in entity) {
console.log(entity.id, entity.tags);
if (isNode(entity)) {
console.log(entity.lon, entity.lat);
}
}
}
// Serialize the PBF for a download, upload, or file-system API
const pbfBytes = await toPbfBuffer(osm);
console.log(`Serialized ${pbfBytes.byteLength} bytes`);
// Merge two OSM PBF files
const patchResponse = await fetch("./monaco-patch.pbf");
const patchPbf = new Uint8Array(await patchResponse.arrayBuffer());
const patchOsm = await fromPbf(patchPbf);
const mergedOsm = await merge(osm, patchOsm, {
directMerge: true,
deduplicateNodes: true,
deduplicateWays: true,
createIntersections: true,
});
console.log(mergedOsm.id);The merge-process guide is the authoritative reference for input identity, stage order, defaults, matching and intersection rules, worked examples, and known limitations. The API enables only the stages requested above; merge(base, patch) without options returns the base unchanged.
import { createRemote } from "osmix";
// main.ts
using remote = await createRemote();
const osm = await remote.fromPbf(monacoPbf); // Returns a dataset handle
// Operations run off the main thread
const tile = await osm.getVectorTile([9372, 12535, 15]);
console.log(tile.byteLength);createRemote() adapts to the runtime: cross-origin isolated browsers get a
multi-worker pool sharing data via SharedArrayBuffer, other browsers get a
fully supported single worker, and Node/test environments can opt into
running on the calling thread with inProcess: true. See the
environment support matrix
for details, including the COOP/COEP headers required for multi-worker mode.
See each package's README for full API and description.
| Package | Description |
|---|---|
osmix |
Main library packaging all tools into a unified API. |
@osmix/core |
In-memory data structures for storing entities, building indexes, and spatial queries. |
@osmix/pbf |
Low-level PBF protobuf parsing and writing. |
@osmix/json |
Streaming transforms: PBF bytes ↔ typed JSON entities. |
@osmix/load |
Load PBF into Osm indexes, geographic extracts, and PBF export. |
@osmix/geojson |
Convert OSM entities to/from GeoJSON. |
@osmix/geoparquet |
GeoParquet import. |
@osmix/gtfs |
GTFS feed import. |
@osmix/shapefile |
Shapefile import. |
@osmix/change |
Deduplication, merging, and changeset workflows. |
@osmix/raster |
Render OSM entities as raster bitmaps. |
@osmix/cli |
Explore OSM PBF files in an interactive terminal map. |
@osmix/vt |
Encode OSM entities as Mapbox Vector Tiles (MVT). |
@osmix/shortbread |
Shortbread schema vector tiles. |
@osmix/shared |
Utility functions and geometry helpers. |
@osmix/router |
Experimental routing. WIP. |
# Install dependencies
pnpm install
# Run all apps through Portless
pnpm run dev
# Build all packages
pnpm run build
# Run tests
pnpm run test
# Type check
pnpm run typecheck
# Type check complete public documentation examples
pnpm run check:docs
# Format and lint
pnpm run check
# Non-mutating format and lint checks
pnpm run format:check
pnpm run lint:check
# Verify one workspace and its runtime dependents
pnpm run verify:workspace -- @osmix/core
# Verify all non-benchmark workspaces plus dependency and Node smoke checks
pnpm run verify:allWorkspace commands support filtering: pnpm --filter @osmix/merge dev
Development servers use Portless and stable HTTPS URLs: merge.osmix.localhost, inspect.osmix.localhost, extract.osmix.localhost, bench.osmix.localhost, www.osmix.localhost, vt.osmix.localhost, and shortbread.osmix.localhost. The first run creates and trusts a local certificate authority; run pnpm exec portless trust if trust setup was skipped. Branch-backed worktrees add the sanitized branch name as a prefix, while detached worktrees add their Git worktree ID, so concurrent checkouts do not compete for routes. Filtered commands retain the same naming convention.
Set PORTLESS=0 to bypass the proxy and run the underlying development command directly, for example PORTLESS=0 pnpm --filter @osmix/merge dev. Portless proxy and certificate state are user-level state and are not stored in this repository.
verify:workspace accepts a package name or path such as apps/vt-server, follows runtime and development workspace dependencies to include dependents, and runs formatting, typechecking, and tests in dependency order. It is check-only by default; pass --write only when formatting changes are intentional. verify:all excludes the browser benchmark app, whose benchmark script is not a package test.
Complete TypeScript examples are marked check-docs and compiled by check:docs; partial configuration and application-wiring fragments are labeled schematic.
Routing regressions use checked-in Monaco and small generated fixtures. Reports distinguish declared route assertions from policy diagnostics and node-ID lookup from coordinate snapping. The optional local R5 comparison records its own endpoint-resolution and assertion evidence; R5 and large local datasets are not required by the normal test suite or CI.
- www – Main site with interactive examples and package overview (osmix.dev)
- merge – Interactive merge tool for OSM extracts with MapLibre visualization (merge.osmix.dev)
- inspect – Single-dataset viewer: load, search, diagnose duplicates, route (inspect.osmix.dev)
- extract – Bounding-box extracts with strategy and tag filters (extract.osmix.dev)
- bench – Performance benchmarks comparing Osmix with DuckDB-wasm
- vt-server – Example vector tile server implementation
- shortbread – Shortbread schema vector tile server demo
- osmix.dev – Docs, examples, and package overview
- GitHub – Issues and discussions
- OpenStreetMap PBF format
- pnpm workspace documentation
- MapLibre GL JS
- Web Compression Streams API