Library / SDK
manuelbieh/geolib avatar
manuelbieh/geolib

Geolib: basic geospatial math for JavaScript without a dependency tree

Zero dependency library to provide some basic geo functions

4,279 stars333 forksJavaScriptMIT

At a glance

What is it?
Geolib is a zero dependency JavaScript and TypeScript library for distance, bounds, centers and point-in-polygon checks. It is 2D only, and that constraint shapes where it fits.
Who is it for?
Adopt Geolib when you need a handful of coordinate calculations in a browser or Node process and you want them without pulling in a geometry engine. Do not adopt it for altitude-aware work, geodesic buffering, or anything needing a full spatial index: the README states the library is currently 2D.
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?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap Geolib fills between raw math and a full GIS stack

Most applications that touch coordinates need four or five operations and nothing more: how far apart are these two points, what is the center of this set, does this point fall inside this polygon, is this point within five kilometers of that one. Turf.js covers all of that and much more, but it arrives as a set of packages you assemble yourself. Geolib takes the opposite position. The package description calls it a "Zero dependency library to provide some basic geo functions," and the package.json confirms it: the only entries under devDependencies are build and test tooling, and there is no dependencies block at all.

The target reader is a frontend or Node developer who has a list of latitude and longitude pairs and does not want a spatial database. A store locator, a delivery radius check, a map that needs to re-center on a set of markers, a form that accepts coordinates typed as degrees, minutes and seconds. None of those justify PostGIS or a tile server. They justify a function call.

The library is written in TypeScript, and the README points at src/types.ts as the place to learn the input shapes. You do not have to write TypeScript to consume it, but the published typings mean an editor will tell you when you pass a string where a number belongs.

How coordinates are accepted, and why the input flexibility matters

Geolib normalizes input at the boundary. According to the README, every method that takes a coordinate accepts either an object with a lat or latitude property plus a lon, lng or longitude property, or a GeoJSON coordinates array in the order [lon, lat]. That array order is the one GeoJSON mandates and the one most people get backwards, so it is worth repeating: longitude first.

Values may be decimal (53.471) or sexagesimal (53° 21' 16"). That second format is the reason this library exists in the shape it does. Sexagesimal parsing is tedious to write and easy to get wrong, and it appears in enough legacy data and enough user input that a small dedicated parser earns its place.

Distance values are always floats in meters. There is no unit option, no feet, no miles. If your product speaks in miles you convert at the call site. That is a deliberate narrowing rather than an oversight, and it keeps the return types predictable.

The distance functions take a third argument, accuracy, defaulting to 1 meter. Setting it to 0.01 asks for centimeter resolution; setting it to 100 rounds the result to the nearest hundred. The README gives the example that 25428 with an accuracy of 100 becomes 25400. This is rounding, not error correction. A smaller accuracy value does not make the underlying formula more precise, it only stops the library from rounding away digits you asked to keep.

Installing Geolib and measuring your first distance

Installation is a single npm or yarn command. The README lists both, and the package name is geolib.

bash
npm install geolib

After that you have two consumption paths. A CommonJS require works in Node, and a bundler or a native ES module environment can import named functions or the whole namespace. The README recommends importing single functions directly to make use of tree shaking, which matters if you care about the minified bundle size shown on the badge at the top of the README.

js
import getDistance from 'geolib/es/getDistance';

const meters = getDistance(
    { latitude: 51.5103, longitude: 7.49347 },
    { latitude: "51° 31' N", longitude: "7° 28' E" }
);

That call mixes a decimal coordinate with a sexagesimal one and returns a number of meters. The README's own example uses exactly these two points, so it is a safe first smoke test: if you get a plausible three-digit meter value back, the import path and the parser are both working.

The README also shows the W3C Geolocation API pattern, where you pass position.coords straight into getDistance against a fixed point. That works because the browser's coords object carries latitude and longitude properties, which is one of the accepted shapes. If geolocation fails, the error callback in the README example alerts the user rather than throwing.

For browser use without a bundler, the README documents a UMD build loaded with a script tag pointing at lib/geolib.js, after which every function is reachable through window.geolib.

getDistance versus getPreciseDistance, and the cost of the second one

The two distance functions are not interchangeable and the README is explicit about the trade. getDistance uses the Haversine formula. getPreciseDistance uses the Vincenty inverse formula for ellipsoids and is described as more accurate, especially over long distances, but also slower.

Haversine treats the Earth as a sphere. Vincenty treats it as an ellipsoid, which is closer to the truth and matters more the further apart your points are. For a delivery radius check inside one city, the difference is likely below the noise floor of your address data. For a route spanning continents, it is not.

Both functions accept the same three arguments, including accuracy. Both return meters. Nothing in the README quantifies the speed difference, so if getPreciseDistance sits inside a loop over tens of thousands of pairs, measure it yourself rather than assuming. The honest reading of the documentation is that Vincenty is the correct default for long-haul work and Haversine is the pragmatic default for local work, and the library makes you choose rather than choosing for you.

Centers, bounds and the Oklahoma problem

Three functions deal with collections of points, and the README draws a distinction that is easy to miss.

getCenter takes an array of coordinates and returns a single {latitude, longitude} object. getBounds returns {minLat, maxLat, minLng, maxLng}. getCenterOfBounds computes the bounding rectangle first and then returns its center.

The README explains why both center functions exist, using the US state of Oklahoma as the example. getCenter on Oklahoma returns a southern point, because the southern border contains far more nodes than the other sides, and a plain average is pulled toward wherever the points are densest. getCenterOfBounds avoids that by ignoring node density entirely. For polygons that represent political borders, the README says the bounds-based result "may gives a closer result to human expectation." That is a real design decision with a visible consequence, and it is the kind of thing most small geometry libraries leave undocumented.

isPointInPolygon takes a point and an array of polygon vertices and returns true or false. isPointWithinRadius takes a point, a center point and a radius in meters. The README's example checks whether 51.525/7.4575 falls within 5 km of 51.5175/7.4678 by passing 5000 as the radius. Both are boolean predicates, which makes them easy to use as filters.

The 2D constraint is the limitation that decides most adoptions

The README opens with a warning in bold: the library is currently 2D, and altitude or elevation is not supported by any of its functions. This is not a footnote. It rules out terrain-aware distance, line-of-sight checks, and anything involving a digital elevation model.

The second limitation is scope. There is no buffering, no intersection, no union, no spatial index, no nearest-neighbor query over a large set. If you need to find the closest of a million points, Geolib gives you getDistance and a loop, and that loop is your problem. Turf.js and a spatial database both address that case directly.

The third is the accuracy argument being a rounding control rather than an error bound. Passing 0.01 to getDistance does not mean the returned value is accurate to a centimeter. It means the library will not round it to the nearest meter. Haversine on a spherical Earth carries its own error, and the README does not state a figure for it.

Finally, the README does not document any rollback or migration path between major versions. A detailed changelog is referenced at CHANGELOG.md, and that is where you would look before upgrading across a major boundary.

Turf.js is the alternative, and the difference is packaging philosophy

Turf.js is the comparison anyone researching this library will encounter, and the two projects differ in approach rather than in the specific formulas they implement.

Turf is a modular geospatial analysis toolkit. It covers measurement, transformation, interpolation, classification and more, published as individually installable packages so you can pull in only the modules you use. Geolib is a single package with a fixed set of functions and no runtime dependencies at all. The package.json shows no dependencies block, and the README's opening line makes the zero dependency claim the headline.

That difference has practical consequences. With Turf you get a much wider surface area and you manage a set of packages. With Geolib you get one import and a smaller API to learn. If your requirement is distance, bounds, center and point-in-polygon, Geolib covers it and stops. If your requirement is anything beyond that, you will end up in Turf or in a proper spatial engine, and the time spent learning Geolib's API is not wasted but it is also not reusable.

There is no Python equivalent under this name. Searches for a geolib Python package are looking for something else entirely.

Maintenance, licence and what an upgrade actually costs

The repository is not archived. The last push was on 2026-04-03, and the most recent release, v3.3.14, was published the same day. The gap before that is informative: v3.3.4 landed on 2023-06-01 and v3.3.3 on 2021-10-11. This is a library that sits quiet for long stretches and then gets a maintenance release, which is consistent with a small, stable API rather than an abandoned project.

The release tooling is automated. package.json defines a release script that runs semantic-release, with @semantic-release/changelog and @semantic-release/git among the dev dependencies, and publishConfig sets provenance to true. That means published artifacts carry a signed build attestation, which is a meaningful supply chain property for a package you are about to put in a browser bundle.

Licensing is MIT, per the LICENSE file and the license field in package.json. MIT is permissive: it allows commercial and closed-source use with the copyright notice and permission notice retained. That is a description of the terms, not legal advice, and if your organisation has a policy on attribution in distributed bundles, read the file.

Upgrade cost is low by construction. The API is a flat set of functions with no configuration object, no plugin registry and no global state, so a version bump is unlikely to require code changes outside the functions you actually call. The CHANGELOG.md at the repository root is the place to confirm that before you bump a major version.

Editorial conclusion

Adopt Geolib when you need a handful of coordinate calculations in a browser or Node process and you want them without pulling in a geometry engine. Do not adopt it for altitude-aware work, geodesic buffering, or anything needing a full spatial index: the README states the library is currently 2D. Before you commit, check the accuracy argument on getDistance against your own tolerance, and confirm whether the Haversine result or the Vincenty result in getPreciseDistance is the one your feature actually needs.

Frequently asked questions

How do I install Geolib?

Install it from npm with npm install geolib, or yarn add geolib. The README also documents a UMD build at lib/geolib.js for loading with a script tag in the browser, where the functions become available on window.geolib.

Does Geolib support altitude or elevation?

No. The README states that the library is currently 2D and that altitude or elevation is not yet supported by any of its functions.

What units does Geolib return distances in?

Meters. The README states that distance values are always floats and represent the distance in meters. There is no unit parameter, so conversion to other units happens at the call site.

What is the difference between getDistance and getPreciseDistance in Geolib?

getDistance uses the Haversine formula, while getPreciseDistance uses the Vincenty inverse formula for ellipsoids. The README describes the second as more accurate especially for long distances, but also slower, and both take the same arguments and return meters.

Official sources

  1. Issues
  2. License: MIT
  3. manuelbieh/geolib on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/manuelbieh-geolib.svg)](https://hysenlabs.com/projects/manuelbieh-geolib)