Terra Draw: one drawing layer that works across six map libraries
A library for drawing on maps that supports Mapbox, MapLibre, Google Maps, OpenLayers and Leaflet out the box
At a glance
- What is it?
- Terra Draw is a MIT licensed TypeScript library that centralises map drawing logic behind an adapter layer, so the same drawing modes work on Leaflet, OpenLayers, MapLibre GL JS, Google Maps, Mapbox GL JS and the ArcGIS JavaScript SDK. The adapters ship as separate packages, and custom modes are a first-class extension point.
- Who is it for?
- Terra Draw is a good pick for a team that has to support more than one mapping library, or that plans to switch between them, because the drawing behaviour, the mode set and the GeoJSON output live in the core rather than in the map library, and the adapter packages mean you only depend on the one you need; it is the wrong pick if your application uses exactly one map library and needs a single unusual drawing gesture, since the adapter layer and the mode architecture are overhead in that case, and before you commit you should read the adapters guide, because the supported library versions are pinned per adapter and the version in your existing map library decides which adapter release you can use.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The adapter layer is the whole architecture
Terra Draw is a library for drawing on maps that supports Mapbox, MapLibre, Google Maps, OpenLayers and Leaflet out of the box, and the readme pitches it as frictionless map drawing across mapping libraries.
The stated approach is that Terra Draw centralizes map drawing logic and provides a host of out-of-the-box drawing modes that work across different JavaScript mapping libraries. The word centralizes is the important one. The drawing behaviour is not implemented once per map library, it is implemented once in the core, and a thin adapter translates between the core's abstractions and each map library's own API.
The core uses the concept of adapters to allow it to work with a host of different mapping libraries, and the built-in adapters are exposed as different packages in the monorepo. Each supported library has its own npm package and a pinned supported version.
Each supported library has its own npm package and a pinned supported version: Leaflet v1 through terra-draw-leaflet-adapter, OpenLayers v10 through terra-draw-openlayers-adapter, MapLibre GL JS v4 and v5 through terra-draw-maplibre-gl-adapter, the Google Maps JS API v3 through terra-draw-google-maps-adapter, Mapbox GL JS v3 through terra-draw-mapbox-gl-adapter, and the ArcGIS JavaScript SDK v4 through terra-draw-arcgis-adapter. The version column is the part to read carefully, because a supported version is a claim about what the adapter has been tested against, and it is a constraint on your application. If your application is on Leaflet v1 you are fine, but the table is a short list of specific versions rather than a range, so an application on MapLibre v3 has no matching adapter release to point at.
One design decision worth noting: the map library is a peer of the drawing layer, not a dependency of it. The core does not pull in Mapbox or Leaflet, and the adapter packages are separate installs. That means the core stays small and the dependency graph of your application stays under your control.
Out-of-the-box modes, and bringing your own
The library ships a set of drawing modes and, more interestingly, treats custom modes as a normal way to use it rather than an escape hatch. The README puts it plainly: it also allows you to bring your own modes.
That framing is the point of the adapter architecture. A drawing mode is behaviour that reacts to pointer input, maintains some state, and emits geometry, and the difference between map libraries is entirely in how pointer events arrive, how layers are created and updated, and how the map reports its current projection and zoom. Once those are normalised by an adapter, a mode written against the core is portable.
The readme gif shows a geodesic line being drawn in Leaflet, and the repository topics list geodesic and geojson, which tells you two things about the geometry model. Geodesic drawing means the mode draws a path measured on the sphere rather than in screen space, which is the behaviour you want on a web map where a straight screen line is not a straight line on the ground. And GeoJSON in the topic list means the output format is GeoJSON, the standard interchange format for vector features, which is what makes the output usable by anything else in the stack.
The mode concept also gives you a way to think about scope. A drawing tool is a mode, the behaviour of a mode is a small state machine, and each mode can be enabled independently, so a single map instance can offer several drawing tools that the user switches between. The custom mode story is what keeps a tool like this useful after the built-in set stops covering your case, and it is the piece most similar libraries in this space do not offer at all.
A monorepo with per-package releases and generated changelogs
The repository is a monorepo whose root package is named terra-draw-monorepo, is marked private, and declares workspaces of packages/*.
Releases are per package, not per repository. The readme states that GitHub releases are created when new packages are released, and that automated changelogs are created for each package upon release based on the conventional commits format, with the generated CHANGELOG.md living in the corresponding package folder. The release history confirms the pattern: terra-draw at 1.37.0 alongside terra-draw-maplibre-gl-adapter at 1.5.0 and terra-draw-mapbox-gl-adapter at 1.5.0, all on the same day in October 2026, with the adapter releases trailing the core release by a few minutes.
The tooling matches the convention. The dev dependencies include commitlint with the conventional config, conventional-recommended-bump, and commit-and-tag-version, and there is a .versionrc.js and a github-release.mjs script at the root, plus bump.mjs and update.mjs for version maintenance. The repository uses npm workspaces rather than pnpm, with a package-lock.json at the root.
Testing is Jest with two configurations, jest.config.ts and jest.nocheck.config.ts, the second presumably running the suite with type checking disabled, and the test scripts cover both plus coverage variants. The transform is swc via @swc/jest, and jsdom is the test environment. There is a knip setup for finding unused code, run through the unused script with a VITE_CJS_IGNORE_WARNING environment variable set.
Lint and format are handled by ESLint 9 with a flat config, eslint.config.mjs, and Prettier, and the husky prepare script installs the git hooks. The package is bundled with microbundle, and the API documentation is generated with typedoc.
Guides directory as the primary documentation
The documentation strategy is unusual enough to be worth describing, because it explains why the README is so short.
There is a guides/ directory at the top level, and the readme points into it for everything. The getting started guide is guides/1.GETTING_STARTED.md, the adapters guide is guides/3.ADAPTERS.md, and the development documentation is guides/7.DEVELOPMENT.md, which also carries the contributing guidance under its own contributing heading. The numbering with gaps is visible in the filenames, which suggests the guide set was planned with a fixed outline and some slots are not filled yet.
The installation path is documented rather than printed: the project publishes the core as the terra-draw package and each adapter as its own package on npm, and the getting started guide in the guides directory is where it says to install them. The readme itself does not contain an install command, so the guide is the place to start from.
The API reference is generated and hosted, with auto generated API docs on the Terra Draw website at terradraw.io under the api route, and the docs script in the root package runs typedoc.
The project website is terradraw.io, with the demo site linked from the readme. The website has its own repository, terra-draw-website, and the readme says that anyone interested in contributing to the website should go there, which is a helpful separation between library work and site work.
There is also a sponsorship page in the guides directory, and a contact address at [email protected]. For a project with this many packages and adapters, having a guide per topic rather than a single long document is a reasonable choice, since the reader usually has one question at a time, such as which adapter to install or how to write a mode.
The version pinning problem is the real integration cost
Looking at the supported version table again, the practical difficulty of adopting this library is not the API but the version matrix.
Six mapping libraries, six adapters, and for each one a specific major version the adapter claims to support. Leaflet v1, OpenLayers v10, MapLibre GL JS v4 or v5, Google Maps JS API v3, Mapbox GL JS v3, ArcGIS JavaScript SDK v4. A team running Leaflet v2, or OpenLayers v9, or MapLibre v3, is outside the range the adapters advertise.
This is the normal situation for adapter libraries and it is worth being honest about what it costs. The adapters are released on their own version lines, as the release history shows with the MapLibre and Mapbox adapters at 1.5.0 while the core is at 1.37.0, so the adapter version is not the core version, and an application has to track two version numbers. The core moves fast because it carries the drawing modes, and the adapters move slowly because they are bound to a third party API that changes rarely.
The mitigation is that the core carries the bulk of the behaviour, so when a new map library version appears, the fix is usually a small adapter change rather than a rewrite. But it is a wait, and the wait belongs to the adapter maintainer.
The other thing the table implies is that Mapbox GL JS and MapLibre GL JS are treated as separate entries, which is right, since they are different libraries with different APIs despite similar names, and the fact that both have maintained adapters suggests the project treats the open source fork as a first class citizen rather than an afterthought.
Where the library is the wrong choice
There is a case where this architecture is pure overhead, and it is worth naming.
If your application uses exactly one map library and never plans to change it, then the adapter layer buys you nothing. You would install the core and one adapter, and every drawing mode would have been simpler to write directly against the map library's own API, with full access to its rendering and event model rather than the subset the adapter normalises. The adapter has to expose a common denominator across six APIs, and that common denominator is by definition smaller than any one of them.
There is a second case, which is the reverse. If you need a drawing capability that none of the built-in modes cover and you are not willing to write a custom mode, this library will not help you, and a targeted implementation against your map library will be faster.
A third limitation is that the output is GeoJSON. For a drawing library that is the right default, since it is the interchange format, but if your downstream system expects a vendor-specific geometry type, the conversion is your problem. The topics list GeoJSON and geometry, so geometry is clearly a first class output, but the specific formats are worth checking against your pipeline before you commit.
Finally, the library is a rendering and interaction layer, not a data model. It does not tell you how to store the drawn features, how to version them, or how to resolve conflicts when two people edit the same polygon. If your application needs collaborative editing or a server-side geometry pipeline, that is a separate system, and the boundary between the two is worth drawing before you start.
Editorial conclusion
Terra Draw is a good pick for a team that has to support more than one mapping library, or that plans to switch between them, because the drawing behaviour, the mode set and the GeoJSON output live in the core rather than in the map library, and the adapter packages mean you only depend on the one you need; it is the wrong pick if your application uses exactly one map library and needs a single unusual drawing gesture, since the adapter layer and the mode architecture are overhead in that case, and before you commit you should read the adapters guide, because the supported library versions are pinned per adapter and the version in your existing map library decides which adapter release you can use.
Frequently asked questions
Which mapping libraries does Terra Draw support?
Six, through separate adapter packages: Leaflet v1, OpenLayers v10, MapLibre GL JS v4 and v5, the Google Maps JS API v3, Mapbox GL JS v3 and the ArcGIS JavaScript SDK v4. The core centralises the drawing logic and the adapter translates to each library's API.
How do I get started with Terra Draw?
The getting started guide at guides/1.GETTING_STARTED.md is the entry point, and the auto generated API docs are on the project website at terradraw.io. The adapters guide at guides/3.ADAPTERS.md explains which adapter package to install for your map library.
Can I write my own drawing modes in Terra Draw?
Yes, the readme states that besides the out-of-the-box drawing modes it also allows you to bring your own modes. Because the drawing logic lives in the core and the adapters only normalise the map library API, a mode written against the core is portable across the supported libraries.
How are Terra Draw releases published?
Per package rather than per repository. GitHub releases are created for new packages, and automated changelogs are generated for each package on release from the conventional commits format, with the generated CHANGELOG.md living in the package folder. The core is at 1.37.0, while the MapLibre and Mapbox adapters are at 1.5.0.
What licence is Terra Draw released under?
MIT, with the licence text in the LICENSE file at the repository root. The repository is not archived and the last push was on 2026-10-18, with terra-draw 1.37.0 published on 2026-10-06.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jameslmilner-terra-draw)Was this useful?