# GeoLibre PWA vs. Tauri Desktop: How Offline Behavior Differs in OpenGeos/GeoLibre

> Discover the offline behavior differences between GeoLibre PWA and Tauri desktop builds. Learn how PWA needs initial online access while Tauri offers instant offline use.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: comparison
- Published: 2026-08-04

---

**The GeoLibre PWA requires an initial online visit to install its service worker and cache assets progressively, while the Tauri desktop build ships all core UI assets inside the native binary for immediate offline operation.**

GeoLibre, the open-source geospatial analysis platform from OpenGeos, ships two "offline-ready" builds of the same application. Understanding how **offline behavior differs between the PWA and Tauri desktop builds** is critical for choosing the right deployment for your environment—whether you need browser-based portability or guaranteed offline operation in disconnected field conditions.

## What Makes Each Build "Offline"?

The foundational difference lies in how assets become available without network access.

### PWA: Service Worker Progressive Caching

The Progressive Web App relies on a **Workbox service worker** generated by `vite-plugin-pwa`. This is conditionally enabled only for web builds through the `IS_TAURI_BUILD` guard in [`apps/geolibre-desktop/vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/vite.config.ts) (lines 30-38 and 58-66).

The service worker implements a two-tier caching strategy:

1. **App shell caching** — HTML, core JavaScript, and CSS are cached on first visit
2. **Runtime caching** — Heavy, lazily-loaded assets like DuckDB-WASM and map plugins are cached on first use

```typescript
// vite.config.ts — the IS_TAURI_BUILD guard disables PWA plugin for desktop
const IS_TAURI_BUILD = process.env.TAURI_ENV_PLATFORM !== undefined;

const pwaPlugin = IS_TAURI_BUILD
  ? null // No service worker for Tauri builds
  : VitePWA({
      // Workbox configuration with runtimeCaching rules...
      runtimeCaching: [
        {
          urlPattern: /geolibre-basemaps/,
          handler: 'CacheFirst',
          options: { cacheName: 'geolibre-basemaps' }
        }
      ]
    });

```

### Tauri Desktop: Bundled Native Assets

The **Tauri desktop build** takes a fundamentally different approach. All static assets—JS, CSS, images, and map tiles—are **bundled inside the native binary** at build time. The service worker registration in [`src/main.tsx`](https://github.com/opengeos/GeoLibre/blob/main/src/main.tsx) (lines 36-90) becomes a no-op for desktop builds.

```typescript
// src/main.tsx — service worker registration skipped for Tauri
if (!isTauri()) {
  registerSW({
    onNeedReload() {
      // Defer reload until stale chunk 404s to preserve UI state
    }
  });
}

```

## First-Run Experience Comparison

| Scenario | PWA Behavior | Tauri Desktop Behavior |
|----------|-----------|------------------------|
| Core UI launch | Requires online first visit | **Offline immediately** |
| Heavy engines (DuckDB, PGlite, Pyodide) | Downloaded from jsDelivr on first use, then cached | Downloaded from CDN on first use **unless bundled** |
| Map tiles | Cached after "Download Offline Area" action | Written to local filesystem via same UI |

The PWA's first-run dependency is validated by the end-to-end test in [`e2e/pwa.spec.ts`](https://github.com/opengeos/GeoLibre/blob/main/e2e/pwa.spec.ts) (lines 4-26 and 58-88), which confirms the service worker installation flow and subsequent offline boot capability.

## Basemap and Offline Area Handling

Both builds share the same **"Download Offline Area"** user interface, but the underlying storage mechanism differs:

- **PWA**: Tiles are cached via the Cache API into the `geolibre-basemaps` cache defined in [`vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/vite.config.ts) runtimeCaching rules (lines 21-33)
- **Tauri**: Tiles are written to the local filesystem through [`src/lib/offline-tiles.ts`](https://github.com/opengeos/GeoLibre/blob/main/src/lib/offline-tiles.ts), then served from bundled assets without network requests

```typescript
// src/lib/offline-tiles.ts — used by both builds
import { downloadOfflineArea } from '../lib/offline-tiles';

// Cache current view with 3km radius
downloadOfflineArea({
  radiusMeters: 3000,
  styleUrl: 'geolibre://offline-basemap/example'
});

```

The implementation in [`src/lib/offline-tiles.ts`](https://github.com/opengeos/GeoLibre/blob/main/src/lib/offline-tiles.ts) abstracts this difference—PWA writes to the Cache API, while Tauri writes to the local filesystem.

## Engine Availability: CDN vs. Bundled

Heavy computational engines present the most significant **offline behavior difference** between builds:

| Engine | PWA Source | Tauri Desktop Source |
|--------|-----------|----------------------|
| Pyodide | jsDelivr CDN, cached by service worker | jsDelivr CDN **or** bundled asset |
| PGlite/PostGIS | jsDelivr CDN, cached by service worker | jsDelivr CDN **or** bundled asset |
| Cereus-DB | jsDelivr CDN, cached by service worker | jsDelivr CDN **or** bundled asset |

The cache definition in [`vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/vite.config.ts) (lines 71-84) specifies the `geolibre-cdn-engines` cache for PWA runtime caching. For fully offline Tauri builds, use environment flags to bundle engines directly:

```bash

# Force bundling of heavy engines — no CDN dependency

GEOLIBRE_PGLITE_CDN=0 GEOLIBRE_CEREUS_CDN=0 npm run build

```

When these flags are set to `0`, the build system includes the WASM assets under `/assets/`, making them available without any network request.

## Update and Reload Behavior

### PWA: State-Preserving Lazy Reload

The PWA overrides Workbox's default `autoUpdate` behavior through the `onNeedReload` callback in [`src/main.tsx`](https://github.com/opengeos/GeoLibre/blob/main/src/main.tsx) (lines 92-104). Rather than immediately reloading when a new service worker activates, GeoLibre:

- Keeps the current UI state intact
- Defers reload until a stale lazy chunk triggers a 404
- Coordinates this through `installStaleChunkReload`

### Tauri Desktop: Atomic Binary Replacement

With no service worker, the desktop build eliminates automatic reload entirely. Updates are delivered via:

- The Tauri installer for standard builds
- The native Microsoft Store updater for Store builds

UI state persists across upgrades because assets are replaced atomically by the installer process.

## Environment Detection Patterns

Code that needs to branch based on build type can use these patterns:

```typescript
// Detect active service worker (PWA only)
if (navigator.serviceWorker?.controller) {
  console.log('SW active – offline caching enabled');
}

// Detect Tauri environment (desktop only)
import { isTauri } from './lib/is-tauri';

if (isTauri()) {
  console.log('Running inside Tauri – assets are bundled locally');
}

```

## Summary

- **PWA offline behavior** depends on a Workbox service worker that progressively caches the app shell and engines after an initial online visit—ideal for browser users who can tolerate first-use downloads
- **Tauri desktop offline behavior** bundles core UI assets in the native binary for immediate offline operation, with optional engine bundling via `GEOLIBRE_PGLITE_CDN=0` and `GEOLIBRE_CEREUS_CDN=0`
- Both builds use [`src/lib/offline-tiles.ts`](https://github.com/opengeos/GeoLibre/blob/main/src/lib/offline-tiles.ts) for basemap caching, but store data differently (Cache API vs. filesystem)
- The `IS_TAURI_BUILD` guard in [`vite.config.ts`](https://github.com/opengeos/GeoLibre/blob/main/vite.config.ts) and the conditional registration in [`src/main.tsx`](https://github.com/opengeos/GeoLibre/blob/main/src/main.tsx) are the primary code locations where build-specific offline behavior is determined

## Frequently Asked Questions

### Can the PWA work completely offline after the first visit?

Yes, but only after the service worker installs during the first online visit and all required lazy-loaded engines have been fetched and cached on their first use. The core UI becomes offline-capable immediately after SW installation; heavy engines like DuckDB-WASM require their own first-use download.

### How do I create a Tauri build with no external dependencies?

Set `GEOLIBRE_PGLITE_CDN=0` and `GEOLIBRE_CEREUS_CDN=0` before building. This forces the Vite configuration to bundle the PGlite, PostGIS, and Cereus-DB WASM assets under `/assets/` rather than relying on jsDelivr fetches. The resulting binary requires no network access for any functionality.

### Does the "Download Offline Area" feature work identically in both builds?

The user interface is identical, but the storage backend differs. The PWA uses the Cache API with the `geolibre-basemaps` cache; the Tauri build writes tiles to the local filesystem. Both are accessed through [`src/lib/offline-tiles.ts`](https://github.com/opengeos/GeoLibre/blob/main/src/lib/offline-tiles.ts), which abstracts this implementation difference.

### Why does the PWA need update handling code that Tauri doesn't?

The PWA's service worker requires explicit coordination to preserve UI state during updates—GeoLibre overrides `onNeedReload` to defer reload until necessary. Tauri updates happen at the binary level through the native installer, which replaces assets atomically without requiring in-application reload logic.