How to Package GeoLibre for Deployment: A Complete Guide to 4 Distribution Formats

GeoLibre supports four deployment formats—static web app, Docker container, native desktop application via Tauri, and embeddable JavaScript package—all built from a single npm workspace-driven pipeline.

GeoLibre is a multi-target GIS platform designed for flexible deployment across environments. Whether you need a lightweight static site, a containerized service, a native desktop application, or an embedded widget for Jupyter notebooks, the build system in opengeos/GeoLibre generates all variants from shared source code. This guide walks through each packaging option with exact commands, configuration files, and environment variables for production-ready deployments.

Prerequisites for Building GeoLibre

Before packaging, verify your toolchain matches the repository requirements:

Tool Minimum Version Purpose
Node.js ≥ 22 (locked in package.json) Powers React UI, Vite builds, and workspace management
npm ≥ 10 (locked by package-lock.json) Installs all workspace dependencies with npm install
Rust + cargo Latest stable Required for Tauri v2 desktop builds
Docker Recent engine Builds container images via Dockerfile
Python 3.10+ Optional sidecar (backend/geolibre_server) and embed package

Run npm install at the repository root to populate all workspace dependencies before any packaging step.

Build the Production Web App

The standard browser deployment produces a self-contained static bundle. In apps/geolibre-desktop/vite.config.ts, Vite compiles the React application, bundles MapLibre GL and DuckDB-WASM, and outputs to dist/.


# Install dependencies

npm ci

# Build the web version (~150 MB uncompressed)

npm run build

The resulting dist/ directory serves directly from any static host: nginx, Cloudflare Pages, GitHub Pages, or AWS S3. The build script is defined in package.json under the "build" entry and invokes Vite via CLI.

Key configuration: apps/geolibre-desktop/vite.config.ts — central Vite configuration shared across web targets.

Deploy as a Docker Container

For self-hosted deployments, the repository provides a minimal nginx-based container. The Dockerfile copies pre-built assets from apps/geolibre-desktop/dist/ into /usr/share/nginx/html.


# Build the image

docker build -t geolibre/web .

# Run on port 80

docker run -d -p 80:80 geolibre/web

The docker-compose.yml at the repository root offers a ready-made configuration for local development or production orchestration.

Build the Native Desktop Application (Tauri v2)

GeoLibre ships native binaries for Windows, macOS, and Linux using Tauri v2. The desktop build reuses the same Vite output, bundling it with a Rust-compiled shell.


# Build Vite assets first (required prerequisite)

npm run build

# Generate desktop installers

npm run tauri:build

Installers appear in apps/geolibre-desktop/src-tauri/target/release/bundle/. The Tauri configuration in apps/geolibre-desktop/src-tauri/tauri.conf.json controls bundle targets, icons, and platform-specific settings. The vite-plugins/copy-vector-ops.ts script handles Python vector operations integration.

Build the CDN-Free "Lite" Version

For air-gapped networks or strict Content Security Policies, the lite build removes all external CDN references. Setting GEOLIBRE_NO_EXTERNAL_CDN=1 vendors DuckDB-WASM, PGlite, CereusDB, and GDAL directly into the bundle.

GEOLIBRE_NO_EXTERNAL_CDN=1 npm run lite:build

The scripts/lite-build.mjs script implements this flag, adjusting Vite plugins to inline all external dependencies. This is the recommended target for corporate intranets and sandboxed environments where external network requests are prohibited.

Create an Embed Package for Jupyter and Custom Front-Ends

GeoLibre publishes as @geolibre/embed, an npm package that bundles the web UI for JavaScript consumption. The build-embed.mjs script generates this package:


# Produce embed bundle to apps/geolibre-desktop/dist-embed

npm run build:embed

The script rewrites entry points and prepares package.json for npm publish. For Python integration, python/hatch_build.py pulls this bundle into the geolibre wheel, enabling Jupyter notebook embedding without separate npm installation.

Customize Builds with Environment Variables

GeoLibre exposes build-time environment variables for private deployments without source modifications:

Variable Purpose Example
VITE_PROTOMAPS_API_KEY Unlock Protomaps basemap VITE_PROTOMAPS_API_KEY=YOUR_KEY npm run build
VITE_PYODIDE_INDEX_URL Point Pyodide to internal mirror VITE_PYODIDE_INDEX_URL=https://mirrors.example.com/pyodide npm run build
GEOLIBRE_EMBED_ORIGINS Permit specific origins via postMessage GEOLIBRE_EMBED_ORIGINS=https://my.corp/app npm run build
GEOLIBRE_NO_EXTERNAL_CDN Remove all GeoLibre-controlled CDN URLs GEOLIBRE_NO_EXTERNAL_CDN=1 npm run lite:build
GEOLIBRE_SHARE_URL Override default sharing endpoint GEOLIBRE_SHARE_URL=https://share.mycompany.com npm run build

These variables are read at Vite build time in apps/geolibre-desktop/vite.config.ts and many are runtime-configurable through the Settings dialog.

Complete CI/CD Packaging Pipeline

For automated builds, combine all targets in a single script:

#!/usr/bin/env bash
set -euo pipefail

npm ci
npm run build                                    # Standard web bundle

GEOLIBRE_NO_EXTERNAL_CDN=1 npm run lite:build    # Air-gapped version

npm run tauri:build                              # Desktop installers

npm run build:embed                              # npm embed package

docker build -t geolibre/web .                   # Container image

The repository's .github/workflows/ci.yml implements this exact sequence in its "test-build" job, verifying artifact integrity on every commit.

Production Docker Deployment

Behind a reverse proxy, deploy the built image with environment-specific configuration:

version: "3.9"
services:
  geolibre:
    image: geolibre/web:latest
    restart: unless-stopped
    ports:
      - "80:80"
    environment:
      - GEOLIBRE_NO_EXTERNAL_CDN=1

The Vue-style service worker in src/main.tsx manages caching and offline operation once deployed.

Verify Your Build

Each packaging target includes automated validation:

Target Test Command
Web / Lite npm run test:frontend
Desktop npm run test:frontend (implicit via build)
Embed npm run test:embed
Container docker run --rm -p 8080:80 geolibre/web && curl -I http://localhost:8080

Run npm run ci to execute the full pipeline as configured in .github/workflows/ci.yml.

Summary

  • Static web app: npm run build produces a ~150 MB dist/ directory ready for any static host
  • Docker container: docker build creates an nginx-based image from pre-built assets
  • Native desktop: npm run tauri:build generates Windows, macOS, and Linux installers via Tauri v2
  • Embed package: npm run build:embed creates @geolibre/embed for JavaScript environments and Python wheels
  • Air-gapped builds: GEOLIBRE_NO_EXTERNAL_CDN=1 removes all external CDN dependencies
  • Environment customization: Build-time variables in vite.config.ts tailor deployments without source changes

Frequently Asked Questions

What is the difference between npm run build and npm run lite:build?

The standard build references external CDNs for DuckDB-WASM and other heavy dependencies, keeping bundle size smaller. The lite build with GEOLIBRE_NO_EXTERNAL_CDN=1 vendors all dependencies internally, producing a larger but fully self-contained bundle suitable for air-gapped or high-security environments.

Can I deploy GeoLibre without using Docker?

Yes. The npm run build command outputs static files in dist/ that serve directly from nginx, Apache, Cloudflare Pages, GitHub Pages, or any static host. No containerization is required for web deployments.

How do I customize the desktop application branding?

Edit apps/geolibre-desktop/src-tauri/tauri.conf.json to modify application metadata, icons, and bundle identifiers. For macOS code signing and notarization, configure the tauri.conf.json bundle section with your Apple Developer credentials before running npm run tauri:build.

What Node.js version is required to build GeoLibre?

The repository requires Node.js ≥ 22 as specified in package.json. Using the locked package-lock.json with npm ci ensures reproducible dependency resolution across build environments.

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 →