Self-Hosting GeoLibre with CDN-Free Builds: A Complete Guide to Offline Deployment

Set environment flags like GEOLIBRE_NO_EXTERNAL_CDN=1 during the Vite build process to bundle all WASM engines locally and eliminate external CDN dependencies.

GeoLibre's default web distribution fetches heavy WebAssembly assets—Pyodide, PGlite/PostGIS, CereusDB, gdal3.js, and DuckDB-WASM—from public CDNs such as jsDelivr and unpkg.com. For enterprises, air-gapped networks, or privacy-focused deployments, the codebase provides granular environment flags that control whether each asset is fetched at runtime or bundled into your application. This article explains how to self-host GeoLibre using these CDN-free build options.

Core CDN-Removal Flags

GeoLibre implements a hierarchical flag system in apps/geolibre-desktop/vite.config.ts and docker/Dockerfile. The master flag overrides all others, with individual flags controlling specific engines.

Flag Default Effect when cleared Use case
GEOLIBRE_NO_EXTERNAL_CDN unset Strips all GeoLibre-controlled CDN references. Disables story-map HTML export, ONNX runtime, 3D Tiles Draco/KTX2 decoders, and GDAL export. Forces other CDN flags to 0. Enterprise deployments with strict no-CDN policies
GEOLIBRE_PGLITE_CDN 1 (CDN) Bundles PGlite + PostGIS WASM (~22 MiB) into /assets/ Offline SQL + PostGIS support
GEOLIBRE_CEREUS_CDN 1 (CDN) Bundles CereusDB (Apache Sedona) WASM (~40 MiB) Offline spatial analytics
GEOLIBRE_GDAL_CDN 1 (CDN) Disables gdal3.js export feature entirely When client-side GeoTIFF/COG export is unnecessary
GEOLIBRE_DUCKDB_WASM_CDN 0 (bundled) Moves DuckDB-WASM (~40 MiB) to jsDelivr Cloudflare Pages/Workers deployments (25 MiB asset limit)
VITE_PYODIDE_INDEX_URL jsDelivr URL Redirects Pyodide to a custom mirror Private Pyodide hosting without disabling Python support

These flags are documented in docs/self-hosting.md and docs/getting-started.md.

Building a Fully Offline-Capable Distribution

Complete CDN-Free Build

Eliminate all external GeoLibre CDN references:

GEOLIBRE_NO_EXTERNAL_CDN=1 npx vite build

This configuration:

  • Emits all bundleable assets to /assets/
  • Removes external script tag injections
  • Disables features requiring exclusive CDN URLs (story-map export, object detection, GDAL export)

Trade-offs: Certain advanced capabilities become unavailable. Core GIS functions—vector rendering, raster analysis, 3D Tiles viewing, and the processing toolbox—remain fully operational.

Selective Engine Bundling

Bundle specific WASM engines while retaining other CDN dependencies:

GEOLIBRE_PGLITE_CDN=0 GEOLIBRE_CEREUS_CDN=0 npx vite build

Result: PGlite/PostGIS and CereusDB assets are copied into /assets/, enabling offline SQL processing and Sedona-style analytics without bundling the full CDN-free stack.

Self-Hosting Pyodide on Private Infrastructure

Pyodide requires special handling. The VITE_PYODIDE_INDEX_URL flag redirects fetches without disabling Python support:

VITE_PYODIDE_INDEX_URL=https://my.cdn.example.com/pyodide/ \
GEOLIBRE_NO_EXTERNAL_CDN=1 npx vite build

GeoLibre itself becomes CDN-free; Python + GeoPandas functionality loads from your controlled infrastructure. Mirror the complete Pyodide distribution—including pyodide.asm.wasm, python_stdlib.zip, and package files—to this endpoint.

Docker-Based Self-Hosted Deployment

The repository provides production-ready containerization in docker/Dockerfile and docker/nginx.conf:


# Build the CDN-free bundle

GEOLIBRE_NO_EXTERNAL_CDN=1 npx vite build

# Construct the container image

docker build -t my-geolibre .

# Run with exposed port

docker run -p 8080:80 my-geolibre

The Dockerfile copies ./dist to /usr/share/nginx/html, serving all bundled assets from the same origin. Customize docker/nginx.conf to add your own CDN mirrors or implement additional security headers.

Performance and Architecture Implications

Service Worker Behavior

With bundled assets, the service worker's CacheFirst strategy for CDN engines becomes unnecessary. Assets served from /assets/ leverage standard HTTP caching and same-origin security policies. The vite.config.ts logic adjusts cache rules automatically based on build flags.

Binary Size Budget

Configuration Size Impact
GEOLIBRE_PGLITE_CDN=0 +~22 MiB
GEOLIBRE_CEREUS_CDN=0 +~40 MiB
GEOLIBRE_GDAL_CDN=0 -~40 MiB (complete removal)
GEOLIBRE_DUCKDB_WASM_CDN=1 -~40 MiB (moves to external CDN)

Calculation: A fully bundled desktop installer or web deployment with PGlite and CereusDB but no GDAL export adds approximately 62 MiB to the base build.

Cloudflare Pages Compatibility

Static hosting platforms often enforce per-asset size limits. GeoLibre's DuckDB-WASM flag specifically addresses Cloudflare's 25 MiB threshold:

GEOLIBRE_DUCKDB_WASM_CDN=1 npx vite build

This moves the ~40 MiB DuckDB-WASM distribution to jsDelivr while keeping GeoLibre's own code self-hosted.

Embed Build Customization

The script scripts/build-embed.mjs generates @geolibre/embed, a distributable iframe-compatible version. This build respects the same environment flags:

GEOLIBRE_NO_EXTERNAL_CDN=1 GEOLIBRE_PGLITE_CDN=0 npx vite build
node scripts/build-embed.mjs

Result: A CDN-free embeddable map component suitable for intranet portals or restricted environments.

Critical Source Files Reference

File Purpose
apps/geolibre-desktop/vite.config.ts Reads environment variables, configures Vite build pipeline, service-worker cache rules
docker/Dockerfile Production container assembly, copies bundled assets to Nginx
docker/nginx.conf Static asset serving configuration
docs/self-hosting.md Master CDN-free deployment documentation (#L151)
docs/getting-started.md Per-engine flag reference table (#L590-594)
scripts/build-embed.mjs CDN-free embeddable build generator
packages/processing/src/ort.ts ONNX Runtime WASM URL derivation—CDN flag removes this dependency

Summary

  • Master control: Set GEOLIBRE_NO_EXTERNAL_CDN=1 to eliminate all GeoLibre-managed CDN references
  • Granular bundling: Use individual GEOLIBRE_*_CDN flags to select which WASM engines ship with your build
  • Pyodide flexibility: Redirect to private mirrors via VITE_PYODIDE_INDEX_URL without losing Python support
  • Platform constraints: Enable GEOLIBRE_DUCKDB_WASM_CDN for size-limited static hosts
  • Production deployment: Leverage the provided Docker configuration for same-origin asset serving

Frequently Asked Questions

What features break when I disable all CDNs?

Story-map HTML export, built-in ONNX-based object detection, 3D Tiles Draco/KTX2 decoders, and GDAL export functionality become unavailable. All vector, raster, 3D visualization, and processing toolbox operations continue working because their WASM engines either bundle locally or remain fetchable from infrastructure you control.

Can I self-host Pyodide while keeping other engines on CDNs?

Yes. Set VITE_PYODIDE_INDEX_URL to your private mirror without enabling GEOLIBRE_NO_EXTERNAL_CDN. PGlite, CereusDB, and other engines continue loading from public CDNs while Pyodide fetches exclusively from your specified origin.

How do I verify my build contains no external CDN references?

Inspect the generated index.html and JavaScript chunks in /dist. Search for patterns matching unpkg.com, cdn.jsdelivr.net, or jsDelivr. The vite.config.ts logic strips these URLs when GEOLIBRE_NO_EXTERNAL_CDN is active, and service-worker precache manifests will list only same-origin /assets/ paths.

What's the minimum viable CDN-free configuration for offline desktop use?

For Tauri or Electron deployments targeting offline-first scenarios: build with GEOLIBRE_NO_EXTERNAL_CDN=1 GEOLIBRE_PGLITE_CDN=0. This provides core GIS capabilities plus SQL/PostGIS processing without network dependencies, at a cost of approximately +22 MiB in installer size.

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 →