# How Turf.js Enables Client-Side Vector Processing in GeoLibre

> Discover how GeoLibre leverages Turf.js for powerful client-side vector processing. Analyze GeoJSON FeatureCollections directly in your browser, removing server dependencies.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-07-31

---

**GeoLibre performs spatial operations entirely in the browser using Turf.js algorithms that process GeoJSON FeatureCollections on the main thread, eliminating server dependencies for vector analysis.**

GeoLibre (opengeos/GeoLibre) is an open-source geospatial framework designed for offline-first vector processing. By integrating Turf.js—a modular geospatial engine—at the core of its processing pipeline, the toolkit enables complex geometry operations to execute client-side across web, desktop, and Jupyter environments.

## Architecture of the Processing Pipeline

The vector processing system is built on a plugin-style architecture where each operation is encapsulated as a **ProcessingAlgorithm**. These algorithms reside in the `@geolibre/processing` workspace and are registered in `[registry.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/registry.ts)` before being exposed to the UI.

### The ProcessingAlgorithm Interface

Each algorithm exports a configuration object implementing the `ProcessingAlgorithm` interface. The `[vector-tools.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/vector-tools.ts)` module demonstrates this pattern, exporting tools like `bufferTool` and `centroidTool` that wrap Turf.js functions. Key properties include:

- **`id`** – Unique identifier used by the registry
- **`supportsSidecar`** – Boolean flag indicating whether the operation can run client-side (`true`) or requires the Python sidecar (`false`)
- **`run`** – Method receiving a `ProcessingContext` and executing the Turf transformation

### Client-Side Execution Context

When a user selects an algorithm from the **Processing Menu** in `[ProcessingMenu.tsx](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/layout/toolbar/ProcessingMenu.tsx)`, the application constructs a `ProcessingContext` containing the active layer’s GeoJSON and parameter values. The algorithm’s `run` method then calls `requireFeatures(ctx)` to extract the `FeatureCollection`, ensuring all data remains in the browser’s memory space.

## Built-In Vector Operations Using Turf.js

GeoLibre ships with pre-configured algorithms covering common GIS workflows. These implementations import Turf functions directly and handle GeoJSON validation automatically.

### Buffer and Centroid Calculations

The `bufferTool` in `[vector-tools.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/vector-tools.ts)` demonstrates the standard pattern. It reads numeric parameters using `numberParam(ctx, 'distance')`, invokes `buffer(fc, distance, {units})` from Turf.js (lines 185–192), and adds the result via `ctx.addResultLayer` (lines 94–95). The implementation handles both single features and collections, wrapping outputs in `featureCollection` to maintain consistent schema.

```typescript
import { bufferTool } from '@geolibre/processing/src/vector-tools';

// ProcessingContext automatically populated by the UI
bufferTool.run(ctx);

```

### Spatial Statistics

For analytical operations, `[statistics-tools.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/statistics-tools.ts)` provides Turf-based measurements including area, bounding box (bbox), and centroids. These functions operate identically to the geometry tools but return scalar values or summary statistics rather than new geometries, enabling attribute table calculations without leaving the client.

## Creating Custom Turf.js Algorithms

Developers can extend the processing menu by authoring new `ProcessingAlgorithm` objects that invoke any Turf.js function. The following example implements a convex hull operation:

```typescript
import convex from '@turf/convex';
import { featureCollection } from '@turf/helpers';
import type { ProcessingAlgorithm, ProcessingContext } from '@geolibre/processing/src/types';

export const convexHullTool: ProcessingAlgorithm = {
  id: 'convexHull',
  name: 'Convex Hull',
  description: 'Create a convex hull polygon around all points',
  group: 'Geometry',
  supportsSidecar: true,
  parameters: [{ id: 'layer', label: 'Input layer', type: 'layer', required: true }],
  run: (ctx: ProcessingContext) => {
    const fc = requireFeatures(ctx);
    if (!fc) return;
    const hull = convex(fc);
    if (hull) ctx.addResultLayer?.('Convex Hull', hull);
  },
};

```

After creating the file, register the export in [`registry.ts`](https://github.com/opengeos/GeoLibre/blob/main/registry.ts) to surface the tool in the Processing Menu. Because `supportsSidecar` is set to `true`, this operation executes entirely in the browser using Turf’s JavaScript implementation, even in the Tauri desktop build.

## Advanced Direct Turf.js Integration

For workflows requiring custom logic beyond the standard algorithm wrapper, you can import Turf functions directly and manipulate GeoJSON collections. This pattern mirrors the pairwise processing used internally in [`vector-tools.ts`](https://github.com/opengeos/GeoLibre/blob/main/vector-tools.ts), which caps iterations at `MAX_CLIENT_PAIRS` to prevent blocking the main thread:

```typescript
import { featureCollection } from '@turf/helpers';
import intersect from '@turf/intersect';
import type { FeatureCollection, Feature } from 'geojson';

function intersectLayers(
  fcA: FeatureCollection, 
  fcB: FeatureCollection
): FeatureCollection {
  const results: Feature[] = [];
  
  for (const fA of fcA.features) {
    for (const fB of fcB.features) {
      const inter = intersect(fA as any, fB as any);
      if (inter) results.push(inter as Feature);
    }
  }
  
  return featureCollection(results);
}

```

This approach is useful for plugins or Jupyter notebook cells where you need to chain multiple Turf operations before adding the final result to the map via the store’s `addResultLayer` method.

## Key Implementation Files

- **[vector-tools.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/vector-tools.ts)** – Implements geometry-heavy algorithms (buffer, union, dissolve) using Turf.js functions. Lines 185–192 contain the buffer implementation; lines 41–59 handle parameter extraction.

- **[statistics-tools.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/statistics-tools.ts)** – Provides spatial statistics (area, bbox, centroid) leveraging Turf’s measurement modules.

- **[registry.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/registry.ts)** – Centralized collection point that imports all `ProcessingAlgorithm` exports and exposes them to the UI layer.

- **[ProcessingMenu.tsx](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/layout/toolbar/ProcessingMenu.tsx)** – React component that instantiates `ProcessingContext` and dispatches algorithm execution based on user selection.

- **[derived-geometry.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/map/src/derived-geometry.ts)** – Auxiliary helpers using Turf for map-side operations like bbox calculation and mask generation.

## Summary

- GeoLibre executes vector processing client-side using **Turf.js** algorithms wrapped in `ProcessingAlgorithm` objects.
- The **[vector-tools.ts](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/vector-tools.ts)** module provides reference implementations for buffering, union, and centroid calculations.
- Algorithms operate on standard **GeoJSON FeatureCollections**, ensuring compatibility with Turf.js and avoiding data serialization to servers when `supportsSidecar` is enabled.
- Custom tools follow the same interface: import a Turf function, extract features via `requireFeatures`, and return results through `ctx.addResultLayer`.
- The architecture runs identically in web browsers, Tauri desktop applications, and Jupyter notebooks due to Turf’s pure JavaScript implementation.

## Frequently Asked Questions

### What is client-side vector processing in GeoLibre?

Client-side vector processing refers to the execution of spatial analysis algorithms—such as buffering, intersection, or centroid calculation—directly within the browser’s JavaScript runtime using Turf.js. As implemented in the `@geolibre/processing` workspace, these operations transform GeoJSON data on the main thread without transmitting information to a remote server or Python sidecar, enabling offline functionality and instantaneous feedback for interactive mapping workflows.

### How does GeoLibre decide between client-side and server-side processing?

Each `ProcessingAlgorithm` declared in the registry includes a `supportsSidecar` boolean flag. When this flag is set to `true`, the system assumes the algorithm can execute using only Turf.js and JavaScript resources, keeping computation on the client. If an algorithm requires Python geospatial libraries (e.g., PySAL or rasterio), `supportsSidecar` is set to `false`, and the `ProcessingContext` routes the request to the Python sidecar instead.

### Can I use Turf.js functions not included in the default processing menu?

Yes. You can import any Turf.js module into a custom algorithm file following the `ProcessingAlgorithm` interface pattern demonstrated in [`vector-tools.ts`](https://github.com/opengeos/GeoLibre/blob/main/vector-tools.ts). After implementing the `run` method to call your desired Turf function—such as `turf.clustersDbscan` or `turf.shortestPath`—export the object and register it in [`registry.ts`](https://github.com/opengeos/GeoLibre/blob/main/registry.ts). The Processing Menu will automatically detect and display the new tool.

### Does GeoLibre's client-side processing work offline?

Yes. Because Turf.js is a pure JavaScript library with no external dependencies, algorithms marked with `supportsSidecar: true` function completely offline once the application is loaded. This design applies to the web build (cached via service workers), the Tauri desktop build (local assets), and the Jupyter extension (local kernel), ensuring vector processing capabilities remain available without network connectivity.