# How to Build and Deploy GeoLibre as a Progressive Web App

> Learn how to build and deploy GeoLibre as a Progressive Web App. Generate a web-ready bundle with a manifest and service worker for static hosting.

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

---

**Build GeoLibre as a Progressive Web App by running `npm run build` in the monorepo root, which generates a web-ready bundle with a Web App Manifest and Workbox service worker in `apps/geolibre-desktop/dist`, ready for static hosting.**

GeoLibre is an open-source geospatial analysis platform that can be distributed as a **Progressive Web App (PWA)** to enable offline functionality and native-like installation without the desktop shell. When you build and deploy GeoLibre as a Progressive Web App, you create a browser-based bundle that caches heavy client-side engines like DuckDB-WASM and Pyodide for offline use. The build process leverages Vite and `vite-plugin-pwa` to automate service worker generation and asset precaching according to the configuration in [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts).

## Prerequisites

Before building the PWA, ensure your environment meets the following requirements:

- **Node.js ≥ 22** and **npm** – The GeoLibre monorepo uses npm workspaces and relies on recent Node.js features for build scripts defined in [`package.json`](https://github.com/opengeos/GeoLibre/blob/main/package.json).
- **Git** – Required to clone the repository.
- **Docker (optional)** – For creating a production-ready nginx image that serves the static PWA files.

## Clone and Install Dependencies

GeoLibre is structured as a single npm workspaces monorepo containing `apps/*`, `packages/*`, and `workers/*` directories. Install all dependencies in one pass:

```bash
git clone https://github.com/opengeos/GeoLibre.git
cd GeoLibre
npm ci

```

The `npm ci` command respects the lockfile and wires up every workspace automatically, preparing the React UI and build toolchain.

## Build the PWA Bundle

Generate the production PWA bundle using the standard build command:

```bash
npm run build

```

This command executes `vite build` configured for the web target in [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts). The build process:

1. Compiles the React UI application located in `apps/geolibre-desktop`.
2. Generates the **Web App Manifest** (`manifest.webmanifest`) and **Workbox service worker** ([`sw.js`](https://github.com/opengeos/GeoLibre/blob/main/sw.js)) via `vite-plugin-pwa`.
3. Outputs static assets to `apps/geolibre-desktop/dist/`.

According to the source code in [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts), the PWA plugin configures caching strategies for the app shell and runtime assets, while the architecture documentation in [`docs/architecture.md`](https://github.com/opengeos/GeoLibre/blob/main/docs/architecture.md) specifies that the service worker precaches the core application shell and implements runtime caching for heavy engines.

## Verify PWA Assets

After the build completes, confirm the presence of required PWA files in the output directory:

```

apps/geolibre-desktop/dist/
├── index.html
├── assets/                 # Hashed JavaScript and CSS chunks

├── manifest.webmanifest    # Web App Manifest

├── sw.js                   # Workbox service worker

└── ...

```

You can verify service worker registration by running this JavaScript in the browser console after serving the dist folder:

```javascript
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.getRegistration().then(reg => console.log('SW registered:', reg));
}

```

The service worker is intentionally bundled only for the web build; the Tauri desktop build disables it since native apps already ship offline assets.

## Deploy the PWA

The `dist/` directory contains static files compatible with any static-file host. Choose one of the following deployment methods:

### Static File Hosting

Serve the `dist/` folder using any basic web server:

```bash
cd apps/geolibre-desktop/dist
python -m http.server 8080

```

Visit `http://localhost:8080` in a PWA-compatible browser to trigger the "Add to Home screen" prompt.

### Docker Production Image

The repository includes a `Dockerfile` that builds the web bundle and wraps it in an nginx container. This configuration copies `apps/geolibre-desktop/dist` into the image and sets up fallback routing to [`index.html`](https://github.com/opengeos/GeoLibre/blob/main/index.html) for single-page application (SPA) navigation:

```bash
docker build -t geolibre-pwa .
docker run -d -p 80:80 geolibre-pwa

```

As implemented in the `Dockerfile`, nginx serves the PWA on port 80 with proper MIME types for the service worker and manifest files.

### Cloud Platforms

Deploy to serverless hosting platforms by configuring the build command and publish directory:

- **Cloudflare Pages** or **Netlify**: Set build command to `npm run build` and publish directory to `apps/geolibre-desktop/dist`.
- **GitHub Pages**: Push the contents of `dist/` to a `gh-pages` branch or use GitHub Actions to automate the build and deploy pipeline.

## Enable Full Offline Support

By default, the service worker precaches the app shell (HTML, core JS/CSS) and runtime-caches heavy engines (DuckDB-WASM, Pyodide, PGlite, CereusDB) after their first network fetch. To embed these engines directly in the bundle for immediate offline availability without a CDN, set environment variables before building:

```bash
GEOLIBRE_PGLITE_CDN=0 GEOLIBRE_CEREUS_CDN=0 npm run build

```

These flags store the engines under `/assets/`, allowing the Workbox service worker to cache them during the initial install event. Refer to the "Offline support (PWA)" section in [`docs/architecture.md`](https://github.com/opengeos/GeoLibre/blob/main/docs/architecture.md) for the complete caching strategy details.

## Summary

- **Install dependencies** with `npm ci` in the monorepo root to prepare the workspace.
- **Build the PWA** by running `npm run build`, which outputs `manifest.webmanifest` and [`sw.js`](https://github.com/opengeos/GeoLibre/blob/main/sw.js) to `apps/geolibre-desktop/dist/` via the Vite configuration.
- **Deploy** the static `dist/` folder using nginx (via the provided `Dockerfile`), Cloudflare Pages, GitHub Pages, or any static host.
- **Optimize offline capability** by setting `GEOLIBRE_PGLITE_CDN=0` and `GEOLIBRE_CEREUS_CDN=0` to embed heavy engines for precaching.

## Frequently Asked Questions

### What is the difference between the GeoLibre desktop app and the PWA version?

The desktop app uses Tauri to wrap the web interface in a native OS shell, while the PWA version runs entirely in the browser using a service worker for offline functionality. Both share the same React codebase, but the PWA is served as static files from `apps/geolibre-desktop/dist` and installs through the browser, whereas the desktop app downloads a native executable.

### Why does the service worker not appear in the desktop build?

The Tauri desktop configuration intentionally disables the service worker because the application assets are already bundled locally with the executable. According to the build logic in [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts), the service worker is only injected for web targets where offline caching is necessary.

### Can I customize the PWA manifest and icons?

Yes, modify the PWA configuration in [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts) where `vite-plugin-pwa` accepts options for the manifest path, theme colors, icon sizes, and caching strategies. After updating, rebuild with `npm run build` to regenerate `manifest.webmanifest` with your customizations.

### How do I update the PWA when deploying a new version?

The Workbox service worker generated by `vite-plugin-pwa` handles updates automatically by precaching new assets and activating a new service worker in the background. Users will see the updated application on the next visit after the new `dist/` files are deployed, as the browser detects changes to [`sw.js`](https://github.com/opengeos/GeoLibre/blob/main/sw.js) and the asset hashes in the precache manifest.