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

> Learn how to package GeoLibre for deployment in four formats: static web app, Docker, Tauri desktop app, and JS package. Streamline your geospatial application distribution.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-08-16

---

**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`](https://github.com/opengeos/GeoLibre/blob/main/package.json)) | Powers React UI, Vite builds, and workspace management |
| **npm** | ≥ 10 (locked by [`package-lock.json`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts), Vite compiles the React application, bundles MapLibre GL and DuckDB-WASM, and outputs to `dist/`.

```bash

# 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`](https://github.com/opengeos/GeoLibre/blob/main/package.json) under the `"build"` entry and invokes Vite via CLI.

**Key configuration:** [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/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`.

```bash

# Build the image

docker build -t geolibre/web .

# Run on port 80

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

```

The [`docker-compose.yml`](https://github.com/opengeos/GeoLibre/blob/main/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.

```bash

# 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`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.conf.json) controls bundle targets, icons, and platform-specific settings. The [`vite-plugins/copy-vector-ops.ts`](https://github.com/opengeos/GeoLibre/blob/main/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.

```bash
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:

```bash

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

npm run build:embed

```

The script rewrites entry points and prepares [`package.json`](https://github.com/opengeos/GeoLibre/blob/main/package.json) for `npm publish`. For Python integration, [`python/hatch_build.py`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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:

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

```yaml
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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/.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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/package.json). Using the locked [`package-lock.json`](https://github.com/opengeos/GeoLibre/blob/main/package-lock.json) with `npm ci` ensures reproducible dependency resolution across build environments.