npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

leaflet-node

v2.0.27

Published

Leaflet for Node.js - Run Leaflet maps in headless Node environments with full TypeScript support

Readme

Leaflet-node

npm version Node.js Version TypeScript

Leaflet-node brings the full Leaflet map API to Node.js so you can render maps without a browser. Reuse the same map setup for server-side image generation, automated tests, and CI pipelines.

Installation

Requirements

Package managers

npm install leaflet-node leaflet
yarn add leaflet-node leaflet
pnpm add leaflet-node leaflet
bun add leaflet-node leaflet

Quick example

import L from 'leaflet-node';

const container = document.createElement('div');
container.style.width = '600px';
container.style.height = '400px';

const map = L.map(container);
map.setView([51.505538, -0.090005], 13);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors'
}).addTo(map);

map.setSize(600, 400);
await new Promise((resolve) => setTimeout(resolve, 1000));
await map.saveImage('map.png');

Testing with Jest

Leaflet-node can run inside Jest with either the default jsdom environment for API-only tests or the node environment for full canvas rendering.

API-only tests (no rendering)

Use the default environment and mock Leaflet to avoid creating a native canvas:

// tests/setup.ts
import { jest } from '@jest/globals';
const L = require('leaflet-node');

jest.doMock('leaflet', () => L);

Rendering tests (with canvas output)

Switch to the node environment so leaflet-node can provide its own jsdom instance and native canvas bindings:

/**
 * @jest-environment node
 */
import L from 'leaflet-node';

test('render map', async () => {
  const container = document.createElement('div');
  const map = L.map(container);

  map.setView([51.505538, -0.090005], 13);
  map.setSize(512, 512);

  await map.saveImage('map.png');
});

Known Issues

Tile Loading Warnings:

You may see warnings about "dynamic import callback" or "experimental-vm-modules" when running tests with tile layers in Jest. This is a Jest limitation with VM modules and doesn't affect the actual rendering—tiles that load successfully are rendered correctly.

To suppress these warnings, you can:

  1. Run Jest with experimental VM modules support:
NODE_OPTIONS='--experimental-vm-modules' jest
  1. Or configure Jest to use isolated modules:
// jest.config.js
export default {
  testEnvironment: 'node',
  globals: {
    'ts-jest': {
      isolatedModules: true
    }
  }
};

[!TIP] Need a ready-to-use map in tests? leaflet-node/testing exposes createTestMap, cleanupTestMaps, waitForTiles, and waitForMapReady helpers that work in both Vitest and Jest.

import { createTestMap, waitForMapReady } from 'leaflet-node/testing';

const map = createTestMap({ width: 400, height: 300 });
await waitForMapReady(map);

Exporting images

Maps can be exported to disk or kept in-memory:

// Save to disk with optional encoder options
await map.saveImage('map.jpeg', { format: 'jpeg', quality: 0.85 });

// Get a Buffer for further processing
const pngBuffer = await map.toBuffer('png');

If you need full control of the canvas, use map.toBuffer() and write the result yourself:

import { promises as fs } from 'fs';

const buffer = await map.toBuffer('png');
await fs.writeFile('map.png', buffer);

Tile loading helpers

Wait for tiles (with optional progress callbacks) before exporting:

import { waitForTiles } from 'leaflet-node/testing';

const layer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
layer.addTo(map);

await waitForTiles(layer, {
  timeout: 60_000,
  onProgress: ({ loaded, total }) => {
    console.log(`Loaded ${loaded}/${total} tiles`);
  },
});

Or wait for every tile layer on a map at once:

import { waitForMapReady } from 'leaflet-node/testing';

await waitForMapReady(map, {
  onTileProgress: (layer, progress) => {
    console.log(layer.getAttribution(), progress);
  },
});

📚 View the full documentation and live examples at jburnhams.github.io/leaflet-node.

Configuring fallback fonts

Leaflet-node automatically attempts to register the bundled Noto Sans fallback fonts. In environments where document.currentScript is unavailable (for example, Node.js test runners without a DOM shim), you can provide an explicit path to the font assets to avoid warning messages:

process.env.LEAFLET_NODE_FONT_BASE_PATH = '/absolute/path/to/NotoSans-Regular.ttf';
const L = await import('leaflet-node');

Alternatively, you can set the base path programmatically after importing the package:

import L, { setFontAssetBasePath } from 'leaflet-node';

setFontAssetBasePath('/absolute/path/to/NotoSans-Regular.ttf');

The base path can point directly to a font file or to a directory containing the bundled NotoSans-Regular.ttf asset.

Proxy configuration

Leaflet-node honours standard proxy environment variables:

export HTTPS_PROXY=http://proxy.example.com:8080
export HTTP_PROXY=http://proxy.example.com:8080

Set them before running exports to route tile downloads through your proxy.

Performance tips

  • Reuse map instances – keep a single map around and update the view instead of creating a new L.map() for every render.
  • Batch exports – kick off multiple independent exports with Promise.all() when your server has headroom.
  • Manage memory – always call map.remove() and drop references once you are done with a map so Node.js can reclaim resources.

Questions? Open an issue on GitHub.