1. Project Overview & Quickstart (maplibre/maplibre-gl-js)
File: README.md
MapLibre GL JS
MapLibre GL JS is an open-source library for publishing maps on your websites or webview based apps. Fast displaying of maps is possible thanks to GPU-accelerated vector tile rendering.
It originated as an open-source fork of mapbox-gl-js, before their switch to a non-OSS license in December 2020. The library's initial versions (1.x) were intended to be a drop-in replacement for the Mapboxβs OSS version (1.x) with additional functionality, but have evolved a lot since then.
Getting Started
Include the CSS file in the <head> of your HTML file.
<link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' />Include the following code in the `` of your HTML file.
<script type='module'>
import * as maplibregl from 'https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.mjs';
const map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json', // stylesheet location
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9 // starting zoom
});
</script>Enjoy the map!
Documentation
Full documentation for this library is available here.
Check out the features through examples.
| Showcases | |
|---|---|
Want an example? Have a look at the official MapLibre GL JS Documentation.
Use MapLibre GL JS bindings for React and Angular. Find more at awesome-maplibre.
Contribution
Getting Involved
Join the #maplibre slack channel at OSMUS: get an invite at https://slack.openstreetmap.us/
Read the CONTRIBUTING.md guide in order to get familiar with how we do things around here.
Avoid Fragmentation
If you depend on a free software alternative to mapbox-gl-js, please consider joining our effort! Anyone with a stake in a healthy community-led fork is welcome to help us figure out our next steps. We welcome contributors and leaders! MapLibre GL JS already represents the combined efforts of a few early fork efforts, and we all benefit from "one project" rather than "our way". If you know of other forks, please reach out to them and direct them here.
MapLibre GL JS is developed followingΒ Semantic Versioning (2.0.0).
Sponsors
We thank everyone who supported us financially in the past and special thanks to the people and organizations who support us with recurring donations!
Read more about the MapLibre Sponsorship Program at https://maplibre.org/sponsors/.
Gold:
Silver:
Backers and Supporters:
Thank you Mapbox ππ½
We'd like to acknowledge the amazing work Mapbox has contributed to open source. The open source community is sad to part ways with them, but we simultaneously feel grateful for everything they already contributed. mapbox-gl-js 1.x is an open source achievement that now lives on as maplibre-gl. We're proud to develop on the shoulders of giants, thank you Mapbox ππ½ββοΈ.
Please keep in mind: Unauthorized backports are the biggest threat to the MapLibre project. It is unacceptable to backport code from mapbox-gl-js, which is not covered by the former BSD-3 license. If you are unsure about this issue, please ask!
License
MapLibre GL JS is licensed under the 3-Clause BSD license.
File: docs/index.md
Introduction
MapLibre GL JS is a TypeScript library that uses WebGL to render interactive maps from vector tiles in a browser.
The mapβs appearance is controlled by a style document whose structure and properties are defined by the MapLibre Style Spec.
It is part of the MapLibre ecosystem, with a counterpart for Android, iOS and other platforms called MapLibre Native.
Quickstart
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.css" />
<script type="module">
import * as maplibregl from 'https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.mjs';
const map = new maplibregl.Map({
container: 'map', // container id
style: 'https://demotiles.maplibre.org/globe.json', // style URL
center: [0, 0], // starting position [lng, lat]
zoom: 2 // starting zoom
});
</script>Reading this documentation
This documentation is divided into several sections:
- Main - The Main section holds the following classes
Mapobject is the map on your page. It lets you access methods and properties for interacting with the map's style and layers, respond to events, and manipulate the user's perspective with the camera.Global Functionslet you set global properties and options that you might want to access while initializing your map or accessing information about its status.
- Markers and Controls - This section describes the user interface elements that you can add to your map. The items in this section exist outside of the map's
canvaselement. This consists ofMarker,Popupand all the controls. - Geography and geometry - This section includes general utilities and types that relate to working with and manipulating geographic information or geometries.
- User interaction handlers - The items in this section relate to the ways in which the map responds to user input.
- Sources - This section describes the source types MapLibre GL JS can handle besides the ones described in the MapLibre Style Specification.
- Event Related - This section describes the different types of events that MapLibre GL JS can raise.
Each section describes classes or objects as well as their properties, parameters, instance members, and associated events. Many sections also include inline code examples and related resources.
In the examples, we use vector tiles from our Demo tiles repository and from MapTiler. Get your own API key if you want to use MapTiler data in your project.
npm
Install the MapLibre GL JS package via npm.
npm install maplibre-glYou can then import the MapLibre GL JS module in your project.
import {Map} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
const map = new Map({
container: 'map', // container id
style: 'https://demotiles.maplibre.org/globe.json', // style URL
center: [0, 0], // starting position [lng, lat]
zoom: 1 // starting zoom
});See the ESM section below for setting up the worker URL with your bundler.
ESM
MapLibre GL JS v6 ships as ES modules only (maplibre-gl.mjs). The "module" field in package.json points at the ESM bundle, so bundlers pick it up automatically.
For minimal runnable apps per bundler (Vite, webpack, esbuild, Rollup, Turbopack), see test/integration/bundler/.
Upgrading from v5? See the v5 to v6 migration guide.
Installation
Pick your setup:
=== "Vite"
Use Vite's `?worker&url` query to get a bundled, self-contained worker URL:
```ts
import {Map, setWorkerUrl} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
setWorkerUrl(workerUrl);
const map = new Map({/* β¦ */});
```
Use `?worker&url` rather than plain `?url`: the dist worker imports its
sibling `maplibre-gl-shared.mjs`, and `?url` emits the worker file verbatim
in production builds without that sibling β the worker then fails on its
first import and no vector tiles load. `?worker&url` routes the file
through Vite's worker pipeline, emitting a self-contained chunk. Dev mode
works with either.
If your build uses SSR (TanStack Start, Astro, etc.) and Vite resolves the CommonJS entry on the server, also add:
```ts title="vite.config.ts"
export default defineConfig({
ssr: {noExternal: ['maplibre-gl']}
});
```=== "webpack 5+"
```ts
import {Map, setWorkerUrl} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
setWorkerUrl(new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url).toString());
const map = new Map({/* β¦ */});
```
rspack and rsbuild use the same pattern.
Next.js is an exception, including in its `next build --webpack` mode. See the Turbopack tab.=== "esbuild"
```js title="build.js"
import * as esbuild from 'esbuild';
import {copyFileSync} from 'fs';
await esbuild.build({
entryPoints: ['src/main.ts'],
bundle: true,
outdir: 'dist',
format: 'esm'
});
copyFileSync(
'node_modules/maplibre-gl/dist/maplibre-gl-worker.mjs',
'dist/maplibre-gl-worker.mjs'
);
```
```ts title="src/main.ts"
import {Map, setWorkerUrl} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
setWorkerUrl(new URL('./maplibre-gl-worker.mjs', import.meta.url).toString());
const map = new Map({/* β¦ */});
```=== "Rollup"
```ts title="rollup.config.js"
import copy from 'rollup-plugin-copy';
export default {
plugins: [
copy({
targets: [
{src: 'node_modules/maplibre-gl/dist/maplibre-gl-worker.mjs', dest: 'dist'}
]
}),
/* ... */
]
};
```
```ts title="src/main.ts"
import {Map, setWorkerUrl} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
setWorkerUrl(new URL('./maplibre-gl-worker.mjs', import.meta.url).toString());
const map = new Map({/* β¦ */});
```=== "Turbopack"
Turbopack ships as the default bundler in Next.js, which is where you are most likely to meet it, so the setup below is written for a Next.js app.
Turbopack turns `new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url)` into a hashed asset without emitting the worker's `maplibre-gl-shared.mjs` sibling next to it. The worker then fails on its first import, and the map mounts but never requests a tile. Serve both files from `public/` instead and point `setWorkerUrl` at the worker:
```js title="scripts/copy-maplibre-worker.mjs"
import {copyFileSync, mkdirSync} from 'node:fs';
import {createRequire} from 'node:module';
import path from 'node:path';
const dist = path.join(path.dirname(createRequire(import.meta.url).resolve('maplibre-gl/package.json')), 'dist');
const dest = path.join(process.cwd(), 'public', 'maplibre');
mkdirSync(dest, {recursive: true});
for (const file of ['maplibre-gl-worker.mjs', 'maplibre-gl-shared.mjs']) {
copyFileSync(path.join(dist, file), path.join(dest, file));
}
```
```json title="package.json"
{
"scripts": {
"prebuild": "node ./scripts/copy-maplibre-worker.mjs",
"predev": "node ./scripts/copy-maplibre-worker.mjs"
}
}
```
```ts title="app/map.tsx"
'use client';
import {Map, setWorkerUrl} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
setWorkerUrl('/maplibre/maplibre-gl-worker.mjs');
const map = new Map({/* β¦ */});
```
The script copies both files, not just the worker.
This is because the worker imports `maplibre-gl-shared.mjs` by relative path, so both have to land in the same directory.
The copy happens at build time, from `node_modules`, so it always matches the installed version.
npm lifecycle prefixes match the exact script name, so `prebuild` and `predev` run before `build` and `dev`, but **not** before a custom script like `build:local` - add a matching `pre` hook for those if necessary.
`postinstall` alone won't do it since package managers skip lifecycle scripts when an install has no work to do, and `--ignore-scripts` skips them entirely.
Next.js needs this in both of its bundler modes, `next build` (Turbopack) and `next build --webpack`, since the asset handling above is Next's rather than Turbopack's alone.=== "CDN / No bundler"
Load MapLibre directly from UNPKG as an ES module via a `<script type="module">` tag. See [unpkg.com](https://unpkg.com) for instructions on selecting specific versions and semver ranges.
```html
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.css" />
<script type="module">
import * as maplibregl from 'https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.mjs';
const map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 0],
zoom: 1
});
</script>
```
The worker is auto-detected from the imported module's URL and laundered through a same-origin Blob URL, so cross-origin CDN loading works out of the box.
Under a strict CSP that disallows `blob:` in `worker-src`, set the worker URL explicitly to a same-origin location:
```js
maplibregl.setWorkerUrl('/path/to/maplibre-gl-worker.mjs');
```
See the [Display a map](./examples/display-a-map.md) example for a runnable version.CSP Directives
As a mitigation for Cross-Site Scripting and other types of web security vulnerabilities, you may use a Content Security Policy (CSP) to specify security policies for your website. If you do, MapLibre GL JS requires the following CSP directives:
worker-src 'self' ;
img-src data: blob: 'self' ;MapLibre CSS
The CSS referenced in the Quickstart is used to style DOM elements created by MapLibre code. Without the CSS, elements like Popups and Markers won't work.
Including it with a <link> in the head of the document via the UNPKG CDN is the simplest and easiest way to provide the CSS, but it is also bundled in the MapLibre module, meaning that if you have a bundler that can handle CSS, you can import the CSS from maplibre-gl/dist/maplibre-gl.css.
Note too that if the CSS isn't available by the first render, as soon as the CSS is provided, the DOM elements that depend on this CSS should recover.
2. Official Technical Reference & Guides (maplibre/maplibre-gl-js-docs)
File: README.md
β οΈThis repo is now archivedβ οΈ
All the code related to the generation of the docs, that now resides in https://maplibre.org/maplibre-gl-js/docs can be found in the at the [main repo](https://github.com/maplibre/maplibre-gl-js).
MapLibre GL JS Documentation
The source code for https://maplibre.org/maplibre-gl-js-docs/, the website that hosts API documentation and examples for MapLibre GL JS. A GitHub Actions Workflow is triggered on push to the main branch. This Action builds the static website and deploys it to GitHub Pages by pushing to the gh-pages branch.
Requirements
- Node 18
- npm 9
If you're not sure if your Node and NPM versions are up to date, run nvm use before installing dependencies. If you don't have NVM installed, you can find installation instructions here.
The NPM scripts will not run on Windows, but work perfectly with WSL2.
Setting up the Development Environment
After cloning this repository, run:
npm ci # install dependencies with npmWriting API Documentation
API documentation is written as JSDoc comments and processed with documentationjs in the source code of maplibre-gl-js. This repository fetches the source code through npm packages.
- Classes, methods, events, and anything else in the public interface must be documented with JSDoc comments. Everything outside of the public interface may be documented and must be tagged as
@private. - Text within JSDoc comments may use markdown formatting. Code identifiers must be surrounded by `backticks`.
- Documentation must be written in grammatically correct sentences ending with periods.
- Documentation must specify measurement units when applicable.
- Documentation descriptions must contain more information than what is obvious from the identifier and JSDoc metadata.
- Class descriptions should describe what the class is, or what its instances are. They do not document the constructor, but the class. They should begin with either a complete sentence or a phrase that would complete a sentence beginning with "A
Tis..." or "TheTclass is..." Examples: "Lists are ordered indexed dense collections." "A class used for asynchronous computations." - Function descriptions should begin with a third person singular present tense verb, as if completing a sentence beginning with "This function..." If the primary purpose of the function is to return a value, the description should begin with "Returns..." Examples: "Returns the layer with the specified id." "Sets the map's center point."
@param,@property, and@returnsdescriptions should be capitalized and end with a period. They should begin as if completing a sentence beginning with "This is..." or "This..."- Functions that do not return a value (return
undefined), should not have a@returnsannotation. - Member descriptions should document what a member represents or gets and sets. They should also indicate whether the member is read-only.
- Event descriptions should begin with "Fired when..." and so should describe when the event fires. Event entries should clearly document any data passed to the handler, with a link to MDN documentation of native Event objects when applicable.
Writing Examples
Examples are written as Batfish pages in docs/pages/example. Each example requires two files: an .html file containing the source
code for the example, and a .js file containing example boilerplate and front matter. The front matter should include the following items:
title: A short title for the example in sentence case as a verb phrase.description: A one sentence description of the example in plain text. This description will appear alongside a thumbnail and title on the examples page.topics: An array of topics for the example, seedocs/data/topics.jsonfor a list of topics.thumbnail: The filename of the example's thumbnail image (without the file extension).contentType: example: Set the contentType to equal example.
In content area of the markdown page include an extended description of the example and add links to documentation or other important resources where possible.
In the .html file, write the HTML and JavaScript constituting the example.
- Do not include a MapTiler access token in the example code. The access token will be inserted automatically by the template, using the current logged in user's default public token, or a placeholder `` string if the user is not logged in.
- On commit, Prettier will format the code for all files, including HTML.
Every example must have an accompanying image.
- Ensure that you have a build of the latest
maplibre-gl-jsin the neighboring directory (see below). - Run
npm run create-image <example-file-name>. The script will take a screenshot of the map in the example and save it todocs/img/src/. Commit the image. - Run
npm startto verify that your example image is loading as expected.
For some examples, npm run create-image does not generate an ideal image. In these cases, you can interact with the map after running the command before the screenshot is taken, or take a screenshot yourself by running the site locally with npm start, take a screenshot and save it in the docs/img/src folder.
To regenerate all images, run npm run create-image all. Note that this doesn't support interaction and examples that require manual interaction (e.g. popups) will need to be manually redone afterward. This feature is experimental and may crash before sucessfully generating all examples.
Running the Documentation Server Locally
To start a documentation server locally, run:
npm startThe command will print the URL you can use to view the documentation.
The examples section of the locally run documentation will use the GL JS version located in ../maplibre-gl-js/dist,
so make sure to have a working minified build in your local copy of the maplibre-gl-js repo; clone maplibre-gl-js into the same directory as maplibre-gl-js-docs and run npm run build-dist there).
Committing and Publishing Documentation
When a new GL JS release goes out, the release manager will make a PR that updates this repo's maplibre-gl npm dependency to point to the new release. When updating the npm package, you may need to run npm test -- -u to update Jest snapshots related to the sidebar navigation.
To update or add a new example, PR the relevant changes to this repo. The example will be live once the PR is merged. If this example uses a version of GL JS that isn't yet released, the PR should not be merged until the release is out.
File: docs/pages/example/3d-buildings.md
title: Display buildings in 3D
topics:
- Layers
thumbnail: 3d-buildings
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './3d-buildings.html';"
Use extrusions to display buildings' height in 3D.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/3d-extrusion-floorplan.md
title: Extrude polygons for 3D indoor mapping
topics:
- Layers
thumbnail: 3d-extrusion-floorplan
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './3d-extrusion-floorplan.html';"
Create a 3D indoor map with the fill-extrude-height paint property.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/3d-terrain.md
title: 3D Terrain
topics:
- Layers
thumbnail: 3d-terrain
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './3d-terrain.html';"
Use 3D terrain to show mountains and valleys.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/add-3d-model.md
title: Add a 3D model with three.js
topics:
- Layers
thumbnail: add-3d-model
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './add-3d-model.html';"
Use a custom style layer with three.js to add a 3D model to the map.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/add-3d-model-babylon.md
title: Add a 3D model with babylon.js
topics:
- Layers
thumbnail: add-3d-model-babylon
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './add-3d-model-babylon.html';"
Use a custom style layer with babylon.js to add a 3D model to the map.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/add-a-marker.md
title: Add a default marker
topics:
- Styles
thumbnail: add-a-marker
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './add-a-marker.html';"
Add a default Marker to the map.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/add-image.md
title: Add an icon to the map
topics:
- Styles
- Layers
thumbnail: add-image
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './add-image.html';"
Add an icon to the map from an external URL and use it in a symbol layer.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/add-image-animated.md
title: Add an animated icon to the map
topics:
- Styles
- Layers
thumbnail: add-image-animated
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './add-image-animated.html';"
Add an animated icon to the map that was generated at runtime with the Canvas API.
{{ <Example html={html} {...this.props} /> }}
File: docs/pages/example/add-image-generated.md
title: Add a generated icon to the map
topics:
- Styles
- Layers
thumbnail: add-image-generated
contentType: example
layout: example
hideFeedback: true
language: - JavaScript
products: - MapLibre GL JS
prependJs: - "import Example from '../../components/example';"
- "import html from './add-image-generated.html';"
Add an icon to the map that was generated at runtime.
{{ <Example html={html} {...this.props} /> }}