Contributing to MapLibre GL JS
May 8, 2026 · View on GitHub
Hi, and thanks in advance for contributing to MapLibre GL JS. Here's how we work. Please follow these conventions when submitting an issue or pull request.
Do not violate Mapbox copyright!
In December 2020 Mapbox decided to publish future versions of mapbox-gl-js under a proprietary license. You are not allowed to backport code from Mapbox projects which has been contributed under this new license. Unauthorized backports are the biggest threat to the MapLibre project. If you are unsure about this issue, please ask!
Best Practices for Contributions
MapLibre welcomes contributions from community! This codebase is large and complex, and following these best practices will assist the maintainer team in reviewing your contribution. In general, the project values discussion and communication over process and documentation. However, due to the size and complexity of the code, below are some best practices that have aided contributors.
It is a good idea to discuss proposed changes before proceeding to an issue ticket or PR. The project team is active in the following forums:
- For informal chat discussions, visit the project's Slack Channel.
- For discussions whose output and outcomes should not be ephemeral, consider starting a thread on GitHub Discussions. This makes it easier to find and reference the discussion in the future.
MapLibre software relies heavily on automated testing, and the project includes a suite of unit and integration tests. For both new features and bugfixes, contributions should update or add test cases to prevent regressions.
New Features
For new features, it is usually a good idea to start with an issue ticket. If the feature requires changes to the style specification, an issue ticket should be created in the style specification GitHub repository. Style specification changes are hard to change later, so there will be particularly close scrutiny on changes to the specification.
If possible, it is beneficial to demonstrate proposed new features and assess the performance implications of the proposed change. You can use npm install <location-of-maplibre-source-code> to test changes in an npm context, or npm run build-prod to build a .js package for this purpose.
For more complex proposed features that require deeper discussion, you should consider bringing it up in the Technical Steering Committee meeting for a video discussion with the team about the proposed change. We find that sometimes it's easier to have a focused, face-to-face discussion for more consequential decisions.
The Technical Steering Committee meetings are open to anyone who wants to get involved in the technical direction of the project. These meetings offer a chance for discussion and collaboration on various technical topics. We welcome you to join the meetings if you're interested in getting involved.
Bug Fixes
If you've identified a significant bug, or one that you don't intend to fix yourself, please write up an issue ticket describing the problem. For minor or straightforward bug fixes, feel free to proceed directly to a PR.
Some best practices for PRs for bugfixes are as follows:
- Begin by writing a failing test which demonstrates how the current software fails to operate as expected. Commit and push the branch.
- Create a draft PR which documents the incorrect behavior. This will show the failing test you've just written in the project's continuous integration and demonstrates the existence of the bug.
- Fix the bug, and update the PR with any other notes needed to describe the change in the PR's description.
- Don't forget to mark the PR as ready for review when you're satisfied with the code changes.
This is not intended to be a strict process but rather a guideline that will build confidence that your PR is addressing the problem.
AI-Assisted Contributions
MapLibre welcomes contributors who use AI coding tools, but we must be vigilant to not incorporate copyrighted materials. You are responsible for everything you submit. Maintainers will not merge code that the author cannot explain or defend in review, regardless of how it was produced, and will need to close your PR or issue if you are not able to meet this bar.
The full policy is at maplibre/maplibre/AI_POLICY.md. Please review this policy before submitting a PR or bug report.
Disclosure: Disclose significant AI assistance in your PR (the PR template has a checkbox).
Preparing your Development Environment
CodeSpaces
By creating a code space you should be able to start working immediately after the post create script finishes running. This script basically installs everything written here in the linux part.
macOS
Install the Xcode Command Line Tools Package
xcode-select --install
Install node.js version in .nvmrc
brew install node
Clone the repository
git clone git@github.com:maplibre/maplibre-gl-js.git
Install dependencies for node_canvas (https://github.com/Automattic/node-canvas)
brew install pkg-config cairo pango libpng jpeg giflib librsvg
Install node module dependencies
cd maplibre-gl-js &&
npm install
Apple silicon
If you have one of the newer arm64 machines, you might find that canvas.node or webgl.node can't be found for your architecture. In that case go to node_modules/canvas and node_modules/gl and run:
npm install --build-from-source
If you have installed from non-M1 machine to an M1 machine using Migration Assistant and you had brew installed before, and you get this error when running tests:
dlopen(/Users/[...]/common/temp/node_modules/.pnpm/canvas@2.11.0/node_modules/canvas/build/Release/canvas.node, 0x0001): symbol not found in flat namespace '_cairo_fill'
at Object.<anonymous> (../../common/temp/node_modules/.pnpm/canvas@2.11.0/node_modules/canvas/lib/bindings.js:3:18)
Try
- Uninstall then re-install
brewbrew - Run
arch -arm64 brew install pkg-config cairo pango libpng jpeg giflib librsvg - delete
node_modulesfolder and re-runnpm install
Linux (and by extension GitHub codespaces)
Install git, GNU Make, and libglew-dev
sudo apt-get update &&
sudo apt-get install build-essential git libglew-dev libxi-dev default-jre default-jdk xvfb
If prebuilt binaries for canvas and gl aren’t available, you will also need:
sudo apt-get install python-is-python3 pkg-config libpixman-1-dev libcairo2-dev libpango1.0-dev libgif-dev
Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
Install Node.js from .nvmrc
nvm install
Clone the repository
git clone git@github.com:maplibre/maplibre-gl-js.git
Install node module dependencies
cd maplibre-gl-js &&
npm install
Before you can run the docs, you need to ensure Docker is installed and you have permission to run docker commands without sudo, as explained here in the Docker docs.
Windows
Consider using WSL and follow the above Linux guide or follow the next steps
Install git, node.js (version in .nvmrc), npm and node-gyp.
Clone the repository
git clone git@github.com:maplibre/maplibre-gl-js.git
Install node module dependencies
cd maplibre-gl-js
npm install
Install headless-gl dependencies https://github.com/stackgl/headless-gl#windows
copy node_modules/headless-gl/deps/windows/dll/x64/*.dll c:\windows\system32
Creating a Standalone Build
A standalone build allows you to turn the contents of this repository into maplibre-gl.mjs, maplibre-gl-worker.mjs and maplibre-gl.css files that can be included on an html page.
To create a standalone build, run
npm run build-dist
Once that finishes, you will have a standalone build at dist/maplibre-gl.mjs, dist/maplibre-gl-worker.mjs and dist/maplibre-gl.css. Load it via <script type="module">; the worker URL is auto-detected as a sibling of the loaded module.
Analyze your Standalone Build
MapLibre seeks to keep production bundle sizes small. If your changes involve substantial additions or changes to dependencies, the effects on bundle size can be visualized by running
npm run bundle-stats
Testing changes and Writing Documentation
See docs/README.md
Writing & Running Tests
See test/README.md.
Writing & Running Benchmarks
See test/bench/README.md.
Further guides
See developer-guides directory for guides on the release process and tile lifecycle.
Code Conventions
- We use
errorevents to report user errors. - We use the latest feature that the TypeScript language has to offer including, but not limited to:
let/constfor...ofloops (for arraylike iteration only, i.e. what is supported by Bublé'sdangerousForOftransform)- Arrow functions
- Classes
- Template strings
- Computed and shorthand object properties
- Default parameters
- Rest parameters
- Destructuring
- Modules
The conventions for module exports are:
- No exported "namespace objects" -- modules should export either classes or functions, with an occasional exception as needed for stubbing.
- If a module exports something with the same name as the file name (modulo case), it should be the default export.
- Anything else should be a named export.
To keep code uniformly styled and avoid common mistakes, you can check some files with the following scripts:
npm run lint
npm run lint-css
Additionally, if you're using VSCode, the "Format Document" action or "Editor: Format on Save" should enforce the js, ts, and css formatting for this project by default.
Version Control Conventions
Here is a recommended way to get setup:
- Fork this project
- Clone your new fork,
git clone git@github.com:GithubUser/maplibre-gl-js.git cd maplibre-gl-js- Add the MapLibre repository as an upstream repository:
git remote add upstream git@github.com:maplibre/maplibre-gl-js.git - Create a new branch
git checkout -b your-branchfor your contribution - Write code, open a PR from your branch when you're ready
- If you need to rebase your fork's PR branch onto main to resolve conflicts:
git fetch upstream,git rebase upstream/mainand force push to Githubgit push --force origin your-branch
Changelog Conventions
What warrants a changelog entry?
- Any change that affects the public API, visual appearance or user security must have a changelog entry
- Any performance improvement or bugfix should have a changelog entry
- Any contribution from a community member may have a changelog entry, no matter how small
- Any documentation related changes should not have a changelog entry
- Any regression change introduced and fixed within the same release should not have a changelog entry
- Any internal refactoring, technical debt reduction, render test, unit test or benchmark related change should not have a changelog entry
How to add your changelog?
- Edit the
CHANGELOG.mdfile directly, inserting a new entry at the top of the appropriate list - Any changelog entry should be descriptive and concise; it should explain the change to a reader without context