How GeoLibre's Vector Tools Fallback Mechanism Works Between Turf.js and the Sidecar GeoPandas Engine

GeoLibre automatically routes vector geoprocessing operations to either the in-browser Turf.js engine or the Python-based Sidecar GeoPandas engine based on computational complexity, geometry type compatibility, and explicit user selection.

The opengeos/GeoLibre repository implements an intelligent dual-engine architecture for vector spatial analysis. Most operations run client-side with Turf.js, a pure JavaScript library, but the framework seamlessly falls back to a FastAPI sidecar running GeoPandas when browser performance would suffer or Turf cannot handle the geometry. This article explains the five-step fallback logic implemented in packages/processing/src/vector-tools.ts and how the Sidecar engine completes the processing loop.

The Client-Side Pairwise Limit: MAX_CLIENT_PAIRS

The first guardrail in GeoLibre's fallback mechanism is a hard computational threshold. Before any pairwise geometry operation begins, vector-tools.ts calculates the total number of comparisons required.

// Example: Intersection – client-side limit triggers fallback
const pairs = inputPolys.length * overlayPolys.length;
if (pairs > MAX_CLIENT_PAIRS) {
  ctx.log(
    `Error: intersection needs ${pairs} comparisons (limit ${MAX_CLIENT_PAIRS}); use the Sidecar engine for large layers`,
  );
  return;
}

MAX_CLIENT_PAIRS is set to 250,000. This limit appears in the Intersection algorithm (lines 29–33) and Spatial join operations (lines 34–40). Exceeding this threshold aborts the client-side execution and prompts the user to switch engines. This prevents browser lockups during O(n²) operations on large datasets.

Geometry Explosion: Making Turf Match GeoPandas Behavior

Turf.js operates on single Polygons, whereas GeoPandas natively handles MultiPolygons. GeoLibre bridges this gap through a preprocessing step called geometry explosion.

// Example: Exploding MultiPolygons before Dissolve
const polys = explodeToPolygons(fc.features); // makes Turf behave like GeoPandas
const dissolved = dissolve(featureCollection(polys), { propertyName: field || undefined });
ctx.addResultLayer?.("Dissolve", dissolved);

The explodeToPolygons function (referenced at line 78 in vector-tools.ts) decomposes MultiPolygons into individual Polygon features. This allows tools like Dissolve, Clip, and Union to run client-side while producing results consistent with the Sidecar engine's multipart-aware operations.

Graceful Degradation for Unevaluable Geometry

Certain geometry types cause Turf.js to throw errors—most notably GeometryCollection. Rather than crashing, GeoLibre catches these failures and continues processing.

The helper function matchesPredicate wraps Turf operations in a try-catch block:

// Simplified from vector-tools.ts line 62
function matchesPredicate(/* ... */) {
  try {
    return turfPredicate(geometryA, geometryB);
  } catch {
    return false;
  }
}

When matchesPredicate catches an error, it returns false and the calling function matchFeaturesByLocation increments an unevaluableDropped counter. The UI then notifies the user that features were skipped and that the Sidecar engine would provide a complete result. This transparency ensures users understand when client-side results may be incomplete.

Explicit Fallback for Unsupported Operations

Some operations cannot be implemented with Turf.js at all. Reproject is a canonical example—coordinate system transformations require PROJ or equivalent libraries unavailable in JavaScript.

For these tools, vector-tools.ts logs explicit guidance:

// From reprojectTool.run (line 98)
ctx.log("Reprojection requires the Sidecar or Pyodide engine. Please select an alternative engine.");

This explicit fallback messaging prevents user confusion and directs them to functional alternatives.

Sidecar Request Handling: The GeoPandas Execution Path

When fallback triggers—whether automatic or user-initiated—the Sidecar client takes over. Located in packages/processing/src/sidecar-client.ts, this module:

  1. Receives the same algorithm definition used for Turf operations
  2. Builds a JSON payload with geometries and parameters
  3. POSTs to the FastAPI sidecar endpoint /processing/run
  4. Returns the resulting GeoJSON layer to the UI
// Excerpt from sidecar-client.ts lines 1070–1095
const response = await fetch('/sidecar/processing/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    tool: algorithm.name,
    inputs: serializedLayers,
    options: algorithm.params
  })
});
const result = await response.json();
ctx.addResultLayer?.(algorithm.name, result.geojson);

The sidecar executes the equivalent operation using GeoPandas (or Whitebox for raster tools), ensuring identical results regardless of which engine processed the data.

Summary

GeoLibre's vector tools fallback mechanism balances responsiveness with capability:

  • Performance guardrails: The MAX_CLIENT_PAIRS limit (250,000) prevents browser overload
  • Geometry normalization: explodeToPolygons enables Turf to handle multipart geometries
  • Error resilience: matchesPredicate catches unevaluable geometry and reports drops
  • Clear user guidance: Explicit messages direct users to the Sidecar for unsupported operations
  • Seamless handoff: sidecar-client.ts forwards requests to a GeoPandas-backed FastAPI service

This architecture lets GeoLibre deliver sub-second feedback for small-to-medium datasets while scaling to enterprise-grade workloads through the Sidecar engine.

Frequently Asked Questions

What triggers automatic fallback to the Sidecar engine?

Automatic fallback occurs when pairwise geometry comparisons exceed 250,000 (MAX_CLIENT_PAIRS), when Turf.js throws errors on unsupported geometry types, or when the algorithm explicitly requires capabilities absent from Turf—such as coordinate reprojection.

Can I force the Sidecar engine even for small datasets?

Yes. The GeoLibre UI allows explicit engine selection for any tool. Choosing "Sidecar" or "Pyodide" bypasses Turf.js entirely, sending the operation directly to sidecar-client.ts and the Python backend.

Does the Sidecar engine return identical results to Turf.js?

Yes, by design. The Sidecar's GeoPandas implementations in backend/geolibre_server/app/vector.py mirror the client-side logic, and both engines output standard GeoJSON. Geometry explosion in Turf ensures behavioral consistency for MultiPolygon operations.

What is Pyodide and how does it differ from the FastAPI sidecar?

Pyodide runs Python (including GeoPandas) directly in the browser via WebAssembly, eliminating server round-trips. The FastAPI sidecar is a separate service—ideal for deployments where Python in the browser is impractical or for leveraging server-side resources.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →