What Is Turf.js?
Turf.js is a modular JavaScript library for advanced geospatial analysis. It runs entirely in the browser (or in Node.js) and works natively with GeoJSON. Instead of sending spatial queries to a database server, Turf lets you compute distances, intersections, buffers, and much more client-side — making it ideal for lightweight applications and interactive prototypes.
This tutorial walks through four of the most commonly needed spatial operations: point-in-polygon, buffer creation, nearest-point lookup, and polygon intersection.
Installation
You can install the full Turf package or import individual modules. For most projects, cherry-picking modules keeps your bundle lean:
# Full package
npm install @turf/turf
# Individual modules (recommended for production)
npm install @turf/boolean-point-in-polygon
npm install @turf/buffer
npm install @turf/nearest-point
npm install @turf/intersect
1. Point-in-Polygon
Determine whether a given point falls inside a polygon — a classic GIS operation used for geofencing, area lookups, and location filtering.
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
import { point, polygon } from '@turf/helpers';
const pt = point([-77.034, 38.899]);
const poly = polygon([[
[-77.05, 38.88], [-77.01, 38.88],
[-77.01, 38.92], [-77.05, 38.92],
[-77.05, 38.88]
]]);
const isInside = booleanPointInPolygon(pt, poly);
console.log(isInside); // true or false
Real-world use: Check whether a user's GPS location is inside a delivery zone, a park boundary, or a country polygon.
2. Creating a Buffer
A buffer expands a geometry outward by a given distance, creating a surrounding zone. This is useful for proximity analysis — e.g., "show all features within 500 meters of this road."
import buffer from '@turf/buffer';
import { point } from '@turf/helpers';
const pt = point([-73.9857, 40.7484]);
const buffered = buffer(pt, 0.5, { units: 'kilometers' });
// buffered is a GeoJSON Polygon feature
console.log(buffered.geometry.type); // "Polygon"
Supported units include kilometers, miles, meters, degrees, and radians. You can buffer Points, LineStrings, or Polygons.
3. Finding the Nearest Point
Given a target point and a collection of candidate points, find which candidate is closest. This powers "find the nearest branch / station / hospital" features.
import nearestPoint from '@turf/nearest-point';
import { point, featureCollection } from '@turf/helpers';
const targetPoint = point([-75.343, 39.984]);
const candidates = featureCollection([
point([-75.343, 39.984], { name: 'Station A' }),
point([-75.833, 39.284], { name: 'Station B' }),
point([-75.534, 39.123], { name: 'Station C' })
]);
const nearest = nearestPoint(targetPoint, candidates);
console.log(nearest.properties.name); // "Station A"
console.log(nearest.properties.distanceToPoint); // distance in degrees
Tip: For distance in kilometers, follow up with @turf/distance between the target and the result.
4. Polygon Intersection
Find the overlapping area between two polygons. Useful for calculating shared zones, clipping data to a boundary, or detecting overlap between regions.
import intersect from '@turf/intersect';
import { polygon, featureCollection } from '@turf/helpers';
const poly1 = polygon([[
[-122.801742, 45.48565], [-122.801742, 45.60491],
[-122.584762, 45.60491], [-122.584762, 45.48565],
[-122.801742, 45.48565]
]]);
const poly2 = polygon([[
[-122.520217, 45.535693], [-122.64038, 45.553967],
[-122.720031, 45.526554], [-122.669906, 45.507309],
[-122.520217, 45.535693]
]]);
const intersection = intersect(featureCollection([poly1, poly2]));
if (intersection) {
console.log(intersection.geometry.type); // "Polygon" or "MultiPolygon"
}
Performance Tips
- Simplify large geometries with
@turf/simplifybefore running operations — complex polygons with thousands of vertices are slow to process client-side. - Use bounding box pre-filtering: Before running expensive operations, check if bounding boxes overlap using
@turf/boolean-intersects. - Move heavy work server-side (PostGIS, Shapely) for production applications with large datasets. Turf is best for moderate data sizes or interactive use.
Summary
Turf.js makes sophisticated spatial analysis accessible without needing a GIS server. For front-end developers working with GeoJSON, it fills a critical gap — enabling geofencing, proximity search, buffer zones, and geometric analysis directly in JavaScript. Start with individual modules to keep bundle size manageable, and graduate to server-side tools when data volumes grow.