# How GeoLibre's Python Pyodide Engine Shares Code with the FastAPI Sidecar for Consistent Vector Operations

> Discover how GeoLibre's Python Pyodide engine and FastAPI sidecar share code from a single source for consistent vector operations in browser and server environments. Learn more.

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

---

**GeoLibre ensures identical vector-processing results across browser and server environments by maintaining a single shared Python package (`geolibre`) that both Pyodide and the FastAPI sidecar import from the same source files.**

The open-source GeoLibre project solves a critical challenge in geospatial web applications: running Python vector operations both in the browser and in a native backend without code duplication or result discrepancies. By packaging vector-processing logic once and deploying it to two distinct runtimes, the project eliminates maintenance overhead and guarantees mathematical consistency for geometry operations like buffering, intersection, and union.

## Shared Python Package Architecture

GeoLibre's solution centers on a unified codebase located in `python/src/geolibre/`. This directory contains pure-Python implementations of all vector operations, designed to run under standard CPython (for the sidecar) and Pyodide's WebAssembly-compiled Python (for the browser).

### Key Design Principles

- **Single source of truth**: All geometry functions live in one location, eliminating version drift between client and server
- **Pure-Python compatibility**: The `geolibre` package avoids platform-specific C extensions that would break WebAssembly compilation
- **Identical APIs**: Both runtimes expose the same function signatures and return formats

The core vector operations are defined in [`python/src/geolibre/vector.py`](https://github.com/opengeos/GeoLibre/blob/main/python/src/geolibre/vector.py), implementing methods like `buffer()`, `intersect()`, and `union()` using `geopandas` and `shapely` primitives.

## FastAPI Sidecar Integration

The native backend service at [`backend/geolibre_server/geolibre_server/vector_ops.py`](https://github.com/opengeos/GeoLibre/blob/main/backend/geolibre_server/geolibre_server/vector_ops.py) imports directly from the shared package:

```python

# backend/geolibre_server/geolibre_server/vector_ops.py

from geolibre.vector import buffer, intersect, union

router = APIRouter()

@router.post("/buffer")
def buffer_route(payload: BufferPayload):
    """FastAPI endpoint that mirrors the Pyodide geolibre.vector.buffer call."""
    return {"geojson": buffer(payload.geojson, payload.distance)}

```

This approach provides several advantages:

- **Full native performance**: The sidecar leverages GEOS and PROJ at full speed through standard wheels
- **HTTP accessibility**: JavaScript clients can call vector operations when Pyodide is unavailable or impractical
- **Fallback capability**: The UI transparently routes requests to the sidecar when Pyodide lacks required functionality

## Pyodide Bundle and Runtime Loading

The browser-side implementation follows a multi-stage build and load process to ensure code parity with the server.

### Build-Time Wheel Generation

During the desktop application build, the `geolibre` package is compiled to a WebAssembly-compatible wheel using `pyodide-build` scripts. The resulting artifact (`geolibre-<version>-py3-none-any.whl`) is copied into the Electron/Tauri assets at `apps/geolibre-desktop/dist/`.

### Runtime Loading Mechanism

The JavaScript loader at [`apps/geolibre-desktop/src/lib/pyodide/pyodide-vector-loader.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/pyodide/pyodide-vector-loader.ts) manages Pyodide initialization:

```typescript
// apps/geolibre-desktop/src/lib/pyodide/pyodide-vector-loader.ts
const loadVectorEngine = async (pyodide: any) => {
  // Load the pre-built geolibre wheel into the Pyodide filesystem
  await pyodide.loadPackage(["geolibre"]);
  // Import the identical module used by the FastAPI sidecar
  const vector = pyodide.pyimport("geolibre.vector");
  return vector;
};

const bufferSelected = async (geojson, distance) => {
  const vector = await loadVectorEngine(pyodide);
  // Executes the same function exposed at /vector/buffer
  const result = vector.buffer(geojson, distance);
  return JSON.parse(result);
};

```

The Pyodide configuration at [`apps/geolibre-desktop/src/lib/pyodide/pyodide-config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/pyodide/pyodide-config.ts) declares `geolibre` as a required package, ensuring inclusion in browser builds.

## Shared Implementation Example

The actual buffer operation—used identically by both environments—is implemented in [`python/src/geolibre/vector.py`](https://github.com/opengeos/GeoLibre/blob/main/python/src/geolibre/vector.py):

```python

# python/src/geolibre/vector.py

import geopandas as gpd
from shapely.geometry import shape

def buffer(geojson: dict, distance: float) -> dict:
    """Shared buffer implementation used by both Pyodide and sidecar."""
    gdf = gpd.GeoDataFrame.from_features([geojson])
    gdf["geometry"] = gdf.geometry.buffer(distance)
    return gdf.__geo_interface__

```

When this function is modified—whether to fix a bug, improve performance, or add a parameter—the change propagates automatically to both runtimes upon package rebuild.

## Fallback Strategy for Consistent User Experience

GeoLibre implements transparent fallback logic to handle cases where Pyodide cannot execute a particular operation. The UI queries sidecar status via `/vector/status` and routes requests accordingly:

- **Pyodide path**: Preferred for latency-critical operations and offline functionality
- **Sidecar path**: Used when native dependencies are required or when Pyodide initialization fails

Because both paths execute the same underlying implementation from [`geolibre/vector.py`](https://github.com/opengeos/GeoLibre/blob/main/geolibre/vector.py), users receive mathematically identical results regardless of which runtime handles the request.

## Summary

- **Unified codebase**: The `geolibre` package at `python/src/geolibre/` provides a single source of truth for all vector operations
- **Dual runtime deployment**: Identical code runs in WebAssembly (Pyodide) and native CPython (FastAPI sidecar)
- **Build-time compilation**: `pyodide-build` generates browser-compatible wheels from the same source files used by the server
- **Runtime loading**: [`pyodide-vector-loader.ts`](https://github.com/opengeos/GeoLibre/blob/main/pyodide-vector-loader.ts) initializes the Pyodide environment with the shared package
- **Automatic consistency**: Bug fixes and feature additions apply simultaneously to both execution contexts
- **Graceful degradation**: The UI falls back to HTTP-based sidecar calls when Pyodide is unsuitable

## Frequently Asked Questions

### How does GeoLibre prevent version skew between Pyodide and sidecar implementations?

Both environments import from the identical source tree at `python/src/geolibre/`. The build process generates the Pyodide wheel and installs the native package from the same commit, ensuring function signatures, algorithms, and default parameters remain synchronized.

### What happens when a vector operation requires native C extensions unavailable in WebAssembly?

The UI detects such limitations through capability checks or import failures, then transparently routes the request to the FastAPI sidecar via the `/vector/*` endpoints. The sidecar executes the same function with full native library access and returns the result over HTTP.

### Can users run GeoLibre entirely without the sidecar?

Yes, provided all required vector operations are supported by the Pyodide build. The [`pyodide-config.ts`](https://github.com/opengeos/GeoLibre/blob/main/pyodide-config.ts) file controls which Python dependencies are bundled; pure-Python packages like `geopandas` and `shapely` function correctly in WebAssembly. Operations requiring compiled extensions (some PROJ transformations, for example) necessitate the sidecar.

### Where is the entry point that exposes `geolibre` functions to Pyodide's JavaScript bridge?

The file [`python/src/geolibre/_server.py`](https://github.com/opengeos/GeoLibre/blob/main/python/src/geolibre/_server.py) serves this purpose, exposing the same functions imported by [`vector_ops.py`](https://github.com/opengeos/GeoLibre/blob/main/vector_ops.py) in a format accessible to `pyodide.pyimport()`.