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

> Discover how GeoLibre's vector tools fallback mechanism intelligently switches between Turf.js and GeoPandas for optimal geoprocessing performance and compatibility.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: internals
- Published: 2026-08-04

---

**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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/vector-tools.ts) calculates the total number of comparisons required.

```typescript
// 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**.

```typescript
// 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`](https://github.com/opengeos/GeoLibre/blob/main/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:

```typescript
// 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`](https://github.com/opengeos/GeoLibre/blob/main/vector-tools.ts) logs explicit guidance:

```typescript
// 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`](https://github.com/opengeos/GeoLibre/blob/main/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

```typescript
// 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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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.