How the Optional Python FastAPI Sidecar Integrates for Raster and Vector Processing in GeoLibre

GeoLibre's optional Python FastAPI sidecar provides a local HTTP server that offloads heavy geoprocessing tasks to Python's raster and vector libraries, falling back to browser-based engines when unavailable.

GeoLibre is designed as a lightweight desktop UI that runs primarily in the browser, but geographic information systems often demand computational power beyond what JavaScript can efficiently provide. The project solves this through an optional Python FastAPI sidecar living in backend/geolibre_server/, which exposes REST endpoints for raster and vector operations. This architecture lets the desktop application delegate to Python's rich geospatial ecosystem—including rasterio, contourpy, GeoPandas, Shapely, and NumPy—while maintaining seamless operation when the sidecar is absent.

Sidecar Lifecycle and Availability Detection

The FastAPI sidecar follows an on-demand startup pattern integrated with GeoLibre's Tauri shell.

Startup Mechanism

The desktop application launches the sidecar using uv for reproducible, frozen environments:

uv run --frozen --project backend/geolibre_server

The server binds to 127.0.0.1 by default. For browser builds, Tauri reverse-proxies requests to /sidecar, making the sidecar appear as a same-origin endpoint.

Runtime Capability Advertisement

Before presenting processing options, the UI queries status endpoints that gracefully handle missing dependencies:

  • GET /vector/status — Returns {"available": true} if GeoPandas imports successfully
  • GET /raster/status — Returns {"available": true} if rasterio and contourpy import successfully

Both endpoints catch ImportError exceptions and return friendly JSON failures rather than crashing. This allows the React UI to automatically enable or disable the "Run" button based on actual capability.

Implementation details: backend/geolibre_server/geolibre_server/app/vector.py (lines 61–74) and backend/geolibre_server/geolibre_server/app/raster.py (lines 14–28).

Vector Processing Flow

The vector pipeline handles GeoJSON transformations through a clean separation between HTTP transport and computational logic.

Request Structure

The VectorToolRequest Pydantic model defines the contract:

class VectorToolRequest(BaseModel):
    tool_id: str
    geojson: Optional[Dict] = None
    parameters: Dict = {}

Source: backend/geolibre_server/geolibre_server/app/vector.py, lines 44–48.

Execution Path

The POST /vector/run endpoint in vector.py (lines 77–107) follows this sequence:

  1. Unmarshals the request into VectorToolRequest
  2. Verifies GeoPandas availability via vector_ops.geopandas_import_error()
  3. Invokes geolibre_server.vector_ops.run_vector_tool()—a framework-free module containing the actual algorithms
  4. Returns {"geojson": <result>, "messages": [...]}

The endpoint uses a synchronous function signature, causing FastAPI to run it in a thread pool. This keeps the event loop responsive for status polling while CPU-bound geometry operations execute.

Cross-Platform Consistency

The same vector_ops.py module serves dual purposes. The Vite plugin vite-plugins/copy-vector-ops.ts bundles this file into web builds, enabling a Pyodide fallback that reproduces identical results in browsers without the sidecar. As documented in docs/architecture.md (around line 77), this ensures behavioral parity between desktop and web deployments.

Vector Write-Back Security

Vector operations that modify files undergo strict validation in _validate_write_path (lines 17–53 of vector.py):

  • File extension whitelist
  • Directory existence and writability
  • Conversion root allowlist via GEOLIBRE_CONVERSION_ROOTS

This prevents path traversal attacks and restricts sidecar file system access to explicitly whitelisted locations.

Raster Processing Flow

Raster operations follow an asynchronous job model suited to long-running GDAL processes.

Request Structure

The RasterToolRequest requires explicit paths:

class RasterToolRequest(BaseModel):
    tool_id: str
    input_path: str
    output_path: str
    parameters: Optional[Dict] = None

Source: backend/geolibre_server/geolibre_server/app/raster.py, lines 46–50.

Execution and Background Jobs

The POST /raster/run endpoint in raster.py (lines 38–82):

  1. Validates paths against _is_within_roots() from conversion.py
  2. Calls _start_job() to queue work in the shared conversion job store
  3. Launches an embedded Python script (hillshade, slope, reproject, etc.) that executes rasterio/NumPy code
  4. Parses progress from special marker strings in subprocess output

This design separates job management from processing logic, allowing the UI to poll for completion without holding HTTP connections open.

Status Polling and Results

Raster jobs reuse the conversion job API:

  • GET /conversion/jobs/{id} — Returns current status, progress percentage, and console output
  • Upon completion: {"status": "completed", "output_path": "...", "messages": [...]}

The raster endpoint thus integrates with GeoLibre's existing conversion infrastructure rather than inventing parallel machinery.

Security Architecture: The Conversion Allowlist

Both vector and raster pipelines share a unified security boundary through GEOLIBRE_CONVERSION_ROOTS.

Operation Validation Function Location
Vector file writes _validate_write_path vector.py lines 17–53
Raster input/output _validate_paths Imported from conversion.py

These helpers guarantee that any file path the sidecar touches resides under an explicitly configured directory tree. This mitigates arbitrary file system access even if request payloads are malformed or malicious.

Desktop UI Integration

The React frontend coordinates sidecar availability through its Zustand store:

// Check sidecar availability on startup
async function checkSidecar() {
  const [vec, ras] = await Promise.all([
    fetch('http://127.0.0.1:8765/vector/status').then(r => r.json()),
    fetch('http://127.0.0.1:8765/raster/status').then(r => r.json()),
  ]);
  console.log('Vector sidecar', vec.available);
  console.log('Raster sidecar', ras.available);
}

When both endpoints return available: true, the UI enables a "Run locally (WASM) → Sidecar" toggle. This lets users choose between:

  • Client-side engines (Turf.js or Pyodide) for privacy and offline operation
  • Python sidecar for large files, native GDAL formats, or algorithms unavailable in JavaScript

If the sidecar is unavailable—missing GeoPandas, for instance—the UI automatically falls back to browser-based processing without user intervention.

Practical Usage Examples

Calling the Vector Endpoint

import requests

payload = {
    "tool_id": "buffer",
    "geojson": {
        "type": "FeatureCollection",
        "features": [...]
    },
    "parameters": {"distance": 1000, "units": "meters"}
}

resp = requests.post(
    'http://127.0.0.1:8765/vector/run',
    json=payload
)
result = resp.json()
print(result['geojson'])

Running a Raster Hillshade Job

import requests
import time

# Start job

run_payload = {
    "tool_id": "hillshade",
    "input_path": "/data/dem.tif",
    "output_path": "/output/hillshade.tif",
    "parameters": {"azimuth": 315, "altitude": 45}
}
resp = requests.post(
    'http://127.0.0.1:8765/raster/run',
    json=run_payload
)
job_id = resp.json()['job_id']

# Poll for completion

while True:
    status = requests.get(
        f'http://127.0.0.1:8765/conversion/jobs/{job_id}'
    ).json()
    if status['status'] == 'completed':
        print('Result file:', status['output_path'])
        break
    time.sleep(0.5)

Key Source Files

Component Path Purpose
Sidecar entry point backend/geolibre_server/geolibre_server/app/main.py FastAPI application factory, route registration
Vector HTTP API backend/geolibre_server/geolibre_server/app/vector.py /vector/status, /vector/run endpoints
Shared vector algorithms backend/geolibre_server/geolibre_server/vector_ops.py Framework-free processing logic, Pyodide-compatible
Raster HTTP API backend/geolibre_server/geolibre_server/app/raster.py /raster/status, /raster/run endpoints
Job management & security backend/geolibre_server/geolibre_server/app/conversion.py _is_within_roots, _start_job, polling infrastructure
Runtime detection backend/geolibre_server/geolibre_server/app/runtime.py Environment bootstrap, import error handling
Architecture documentation docs/architecture.md Pyodide bundling strategy, design rationale

Summary

  • On-demand startup: The Tauri shell launches the FastAPI sidecar via uv run when processing demands exceed browser capabilities
  • Graceful degradation: Status endpoints (/vector/status, /raster/status) advertise availability; missing dependencies never crash the server
  • Unified security model: GEOLIBRE_CONVERSION_ROOTS restricts all file operations to whitelisted directories
  • Framework-free algorithms: vector_ops.py runs identically in the sidecar and Pyodide, ensuring consistent results across deployment targets
  • Async job pattern: Raster operations use background jobs with polling, while vector operations leverage FastAPI's thread pool for synchronous CPU work

Frequently Asked Questions

What happens if GeoPandas or rasterio is not installed?

The sidecar starts successfully but returns {"available": false} from the respective status endpoint. The UI detects this and disables the sidecar toggle, falling back to Turf.js for vectors or disabling raster tools entirely. No errors propagate to the user.

Can I use the sidecar with the web/browser build of GeoLibre?

Yes. When building for web, Tauri reverse-proxies the sidecar at /sidecar so the same origin policy is satisfied. Alternatively, you can deploy the FastAPI server independently and configure the UI to point at it—though this requires handling CORS and authentication yourself.

Why does raster processing use background jobs while vector processing does not?

Raster operations typically invoke GDAL through rasterio, which may run for minutes on large datasets. The job model prevents HTTP timeouts and allows progress tracking. Vector operations are usually faster (geometry buffering, intersection, etc.), so FastAPI's default thread pool provides sufficient concurrency without the complexity of job state management.

Is the sidecar required for GeoLibre to function?

No. The application is designed to work entirely in the browser using JavaScript libraries (Turf.js) and WebAssembly (Pyodide). The Python FastAPI sidecar is strictly an optional accelerator for heavy workloads, large files, and formats only readable by GDAL.

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 →