mbtiles-reader
v2.0.1
Published
Reader for MBTiles files.
Downloads
2,567
Readme
MBTiles Reader
Read tiles and metadata from MBTiles files. Works in both Node.js (using better-sqlite3) and browsers (using @sqlite.org/sqlite-wasm).
Installation
npm install mbtiles-readerThe correct entry point is selected automatically via the "browser" condition in package.json. Bundlers like Vite, Webpack, esbuild, and Rollup all support this out of the box.
The platform-specific SQLite drivers (better-sqlite3 for Node.js, @sqlite.org/sqlite-wasm for browsers) are optional dependencies — only the one needed for your platform will be used, and a failed install of the other won't cause errors.
Usage
import { MBTiles } from 'mbtiles-reader'
// Open from a file path (Node.js) or ArrayBuffer/Uint8Array (both platforms)
const mbtiles = await MBTiles.open('path/to/tiles.mbtiles')
// Read a single tile (XYZ coordinates)
const tile = mbtiles.getTile({ z: 0, x: 0, y: 0 })
console.log(tile.format) // 'png', 'jpg', 'webp', or 'pbf'
console.log(tile.data) // Uint8Array
// Iterate over all tiles
for (const { z, x, y, data, format } of mbtiles) {
console.log(`${z}/${x}/${y}: ${data.length} bytes (${format})`)
}
// Access metadata
console.log(mbtiles.metadata)
// { name, format, scheme, minzoom, maxzoom, bounds, center, ... }
mbtiles.close()Opening from a buffer
Both platforms support opening from an ArrayBuffer or Uint8Array:
const response = await fetch('/tiles.mbtiles')
const mbtiles = await MBTiles.open(await response.arrayBuffer())Browser-specific sources
In the browser, MBTiles.open() also accepts a File (e.g. from <input type="file">):
const mbtiles = await MBTiles.open(file)Node.js-specific sources
In Node.js, MBTiles.open() also accepts an existing better-sqlite3 Database instance:
const mbtiles = await MBTiles.open(db)OPFS (Web Worker)
When running in a Web Worker, you can pass an OPFS file path to MBTiles.open() instead of loading the entire file into memory. The consumer is responsible for writing the file to OPFS first:
// In a Web Worker:
// 1. Write the file to OPFS (your responsibility)
const root = await navigator.storage.getDirectory()
const handle = await root.getFileHandle('tiles.mbtiles', { create: true })
const access = await handle.createSyncAccessHandle()
access.write(new Uint8Array(buffer), { at: 0 })
access.flush()
access.close()
// 2. Open by OPFS path — uses OpfsDb, no copy into wasm memory
const mbtiles = await MBTiles.open('tiles.mbtiles')
// 3. Use as normal
const tile = mbtiles.getTile({ z: 0, x: 0, y: 0 })
mbtiles.close()
// 4. Clean up OPFS when done (your responsibility)
await root.removeEntry('tiles.mbtiles')TypeScript
This package includes type declarations for both entry points. TypeScript resolves the correct types based on your moduleResolution setting:
| moduleResolution | Types resolved | MBTiles.open() accepts |
| --------------------------------------------- | ----------------- | ------------------------------------------------- |
| "nodenext" / "node16" | Node.js | string \| ArrayBuffer \| Uint8Array \| Database |
| "bundler" | Node.js (default) | same as above |
| "bundler" + customConditions: ["browser"] | Browser | string \| File \| ArrayBuffer \| Uint8Array |
TypeScript does not set the "browser" condition automatically in any mode. By default, the Node.js types are resolved, which include MBTiles.open() and all shared methods — this works for most browser consumers since the common source types (string, ArrayBuffer, Uint8Array) are the same on both platforms.
If you need browser-specific types (e.g. File support in autocomplete), add customConditions to your tsconfig.json:
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "bundler",
"customConditions": ["browser"],
},
}Bundler configuration
The browser entry point uses @sqlite.org/sqlite-wasm, which loads a .wasm file at runtime. Most bundlers need to be told not to pre-bundle this dependency, so the .wasm file can be resolved and served correctly.
Vite:
// vite.config.js
export default {
optimizeDeps: {
exclude: ['@sqlite.org/sqlite-wasm'],
},
}Webpack and esbuild generally handle this without extra configuration.
API
MBTiles.open(source) → Promise<MBTiles>
Opens an MBTiles database. Throws if the file is missing, corrupt, or not a valid MBTiles file.
source— anArrayBufferorUint8Array(both platforms), file path or better-sqlite3Database(Node.js), orFile/ OPFS path (browser).
In the browser, when source is a string it is treated as an OPFS file path and opened directly with OpfsDb (requires a Web Worker context). This avoids loading the entire database into wasm memory. When source is a File, ArrayBuffer, or Uint8Array, the data is loaded into memory using SQLite's sqlite3_deserialize.
mbtiles.getTile({ z, x, y }) → Tile
Returns the tile at the given XYZ coordinates. Throws if the tile does not exist.
z— zoom levelx— tile columny— tile row (XYZ scheme, not TMS)
Returns a Tile:
| Property | Type | Description |
| -------- | ------------ | -------------------------------------- |
| z | number | Zoom level |
| x | number | Tile column |
| y | number | Tile row |
| data | Uint8Array | Raw tile data |
| format | string | 'png', 'jpg', 'webp', or 'pbf' |
mbtiles.metadata → MBTilesMetadata
Metadata from the MBTiles file per the MBTiles spec. Properties bounds, center, minzoom, and maxzoom are always present — they are derived from the tile data if not set explicitly in the metadata table.
| Property | Type | Description |
| ------------- | --------------------------------------- | ------------------------------------------- |
| name | string | Tileset name (required by spec) |
| format | string | Tile format: png, jpg, webp, or pbf |
| scheme | 'xyz' | Always 'xyz' (TMS rows are converted) |
| minzoom | number | Minimum zoom level |
| maxzoom | number | Maximum zoom level |
| bounds | [w, s, e, n] | Bounding box in WGS84 |
| center | [lng, lat, zoom] | Default center point |
| attribution | string (optional) | Attribution string |
| description | string (optional) | Tileset description |
| version | number (optional) | Tileset version |
| type | 'overlay' \| 'baselayer' (optional) | Layer type |
For pbf (vector tile) tilesets, the json metadata field is parsed and merged, with explicit metadata values taking precedence.
mbtiles[Symbol.iterator]() → IterableIterator<Tile>
Iterates over every tile in the file:
for (const tile of mbtiles) {
/* ... */
}mbtiles.close()
Closes the underlying database. The instance should not be used after calling this.
Coordinate system
MBTiles files store tiles using the TMS coordinate scheme, where y=0 is at the bottom. This library converts to the more common XYZ scheme (used by web maps, where y=0 is at the top) automatically. All coordinates you pass to getTile() and receive from iterators use XYZ.
License
MIT
Acknowledgements
Inspired by mbtiles.
