# How the Tauri v2 Desktop Build Works in the GeoLibre npm Workspaces Monorepo

> Explore how Tauri v2 desktop builds integrate into the GeoLibre npm workspaces monorepo. Understand the bundling of Vite web UI, Rust binaries, and Python sidecar.

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

---

**The GeoLibre repository uses a Tauri v2 desktop build wrapped in an npm workspaces monorepo, where the desktop app at `apps/geolibre-desktop` bundles a Vite-built web UI with native Rust binaries and an optional Python sidecar.**

GeoLibre's **Tauri v2 desktop build** functions as a specialized package within a unified **npm workspaces monorepo**. According to the opengeos/GeoLibre source code, this architecture lets the team maintain all JavaScript/TypeScript packages under `@geolibre/*` namespaces while isolating desktop-specific concerns in a dedicated application folder. The result is a cross-platform native binary that embeds a modern web interface, with build orchestration handled through custom npm scripts and a Node.js build script.

## npm Workspaces Structure and Desktop Package Location

The monorepo root defines workspaces that include all library packages and the desktop application. The desktop client lives at **`apps/geolibre-desktop`** and functions as a standard npm workspace member with its own [`package.json`](https://github.com/opengeos/GeoLibre/blob/main/package.json), dependencies, and build lifecycle.

This structure allows shared dependencies to be hoisted to the repository root while letting the desktop package declare Tauri-specific tooling locally. Other packages in the workspace can import `@geolibre/*` libraries as if they were published modules, enabling code reuse between web and desktop targets.

## Build Scripts and Development Workflow

All Tauri v2 desktop build operations are exposed through npm scripts defined in **[`apps/geolibre-desktop/package.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/package.json)**. These scripts bridge the Vite bundler, TypeScript compiler, and Tauri CLI:

| Script | Purpose |
|--------|---------|
| `npm run dev` | Starts the Vite development server on port 5173 |
| `npm run build` | Runs `tsc -b` across workspaces and produces the production web bundle in `dist/` |
| `npm run tauri:dev` | Launches a hot-reloading Tauri window pointing at `http://localhost:5173` |
| `npm run tauri:build` | Executes the production desktop build pipeline |
| `npm run tauri:build:native-duckdb` | Builds with native DuckDB instead of WebAssembly |
| `npm run tauri:build:mas` | Builds a Mac App Store-compliant package |

The `tauri:dev` script is particularly useful for iterative development. It keeps the Vite dev server running and opens a native window that loads from the dev URL, enabling rapid testing of desktop-specific APIs alongside web UI changes.

## The Custom Build Script: `scripts/tauri-build.mjs`

The core orchestration for production builds happens in **`scripts/tauri-build.mjs`**. This Node.js module parses arguments, sets environment variables, and spawns the Tauri CLI with the correct flags. According to the GeoLibre source code, the script performs these sequential operations:

### Argument Parsing and Flag Detection

The script scans `process.argv` for two optional flags:

- **`--native-duckdb`** — Enables the `native-duckdb` Cargo feature
- **`--mas`** — Enables the `mas` Cargo feature for Mac App Store compliance

These flags are stripped from the argument list before forwarding to the Tauri CLI.

### Platform-Specific Defaults

On Linux systems without explicit bundle arguments, the script automatically appends `--bundles deb,rpm` to produce native package formats suitable for distribution.

### Feature Gating and Environment Injection

The build script translates npm script flags into Cargo features and environment variables:

```javascript
// Simplified logic from scripts/tauri-build.mjs
if (args.includes('--native-duckdb')) {
  cargoFeatures.push('native-duckdb');
}

if (args.includes('--mas')) {
  cargoFeatures.push('mas');
  process.env.GEOLIBRE_STORE_BUILD = '1';
  process.env.GEOLIBRE_MAS_BUILD = '1';
}

```

The **`native-duckdb`** feature swaps the DuckDB query engine from its WebAssembly build to a native binary, significantly improving performance for large geospatial vector and raster operations.

The **`mas`** feature triggers stricter packaging rules. It swaps the Tauri configuration to **[`tauri.mas.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.mas.conf.json)**, and the environment variables `GEOLIBRE_STORE_BUILD` and `GEOLIBRE_MAS_BUILD` signal downstream code to strip prohibited components: the Python sidecar, Jupyter integration, and external download capabilities.

### CLI Execution

Finally, the script assembles the command and spawns the Tauri CLI through the workspace:

```javascript
import { spawnSync } from 'child_process';

const result = spawnSync(
  'npm',
  ['run', 'tauri', '-w', 'geolibre-desktop', '--', 'build', ...finalArgs],
  {
    stdio: 'inherit',
    env: process.env
  }
);

process.exit(result.status ?? 1);

```

The script exits with the same status code returned by the Tauri CLI, ensuring CI/CD pipelines can detect build failures correctly.

## Tauri Configuration Files

### Primary Configuration: [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json)

The main Tauri configuration at **[`apps/geolibre-desktop/src-tauri/tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.conf.json)** defines the desktop application's core properties:

- **Product metadata** — Name, version, and unique identifier
- **Build hooks** — `beforeDevCommand` and `beforeBuildCommand` invoke the npm scripts described earlier
- **Development URL** — `http://localhost:5173` for hot-reload development
- **Security policies** — Content Security Policy (CSP), custom asset protocols, and capabilities that govern IPC and local resource access for the MapLibre-based map view
- **Bundle resources** — Embeds `backend/geolibre_server` (the Python FastAPI sidecar) and specifies icon sets

### Mac App Store Variant: [`tauri.mas.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.mas.conf.json)

When building for the Mac App Store, the build script switches to **[`tauri.mas.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.mas.conf.json)**. This variant removes or restricts capabilities that violate Apple's sandboxing requirements, such as arbitrary code execution and external process spawning.

### Rust Entry Point: [`main.rs`](https://github.com/opengeos/GeoLibre/blob/main/main.rs)

The file **[`apps/geolibre-desktop/src-tauri/src/main.rs`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/src/main.rs)** initializes the Tauri application, registers native plugins (dialog, filesystem, geolocation), and mounts the webview. Feature gates in this file respond to the `native-duckdb` and `mas` Cargo features to conditionally compile platform-specific behavior.

## Complete Build Pipeline Walkthrough

### Standard Desktop Build

Running `npm run tauri:build` executes this sequence:

1. **TypeScript compilation** — `tsc -b` validates types across all workspace packages
2. **Vite bundling** — Produces optimized static assets in `apps/geolibre-desktop/dist/`
3. **Tauri CLI invocation** — `tauri-build.mjs` spawns the Rust compiler with default features
4. **Binary assembly** — The Rust backend embeds the `dist/` folder as `frontendDist`, compiles native dependencies, and links the final executable
5. **Installer generation** — Platform-specific packages (`.app`, `.exe`, `.deb`, `.rpm`) are created in `src-tauri/target/release/bundle/`

### Native DuckDB Build

The **`npm run tauri:build:native-duckdb`** variant adds the `native-duckdb` Cargo feature. This:

- Links against the native DuckDB shared library instead of bundling the WASM module
- Reduces memory overhead and improves query throughput for geospatial datasets
- Increases binary size and platform-specific dependency requirements

### Mac App Store Build

The **`npm run tauri:build:mas`** variant produces a package suitable for Apple notarization:

- Activates the `mas` Cargo feature
- Switches configuration to [`tauri.mas.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.mas.conf.json)
- Disables the Python sidecar, Jupyter integration, and automatic updater
- Sets `GEOLIBRE_STORE_BUILD=1` and `GEOLIBRE_MAS_BUILD=1` for runtime feature detection

## Python Sidecar Integration

The **`backend/geolibre_server`** directory contains a FastAPI application that provides vector/raster processing services. During the Tauri build, this Python environment is packaged as a **sidecar resource** — a separate binary spawned by the Rust backend and communicated with over local IPC. This architecture keeps heavy geospatial computation out of the JavaScript main thread while maintaining a seamless user experience.

The sidecar is excluded from MAS builds per App Store policy, requiring those builds to rely on lighter, sandbox-compatible alternatives.

## Practical Build Commands

```bash

# Clone and install dependencies

git clone https://github.com/opengeos/GeoLibre.git
cd GeoLibre
npm install

# Development with hot reload

npm run tauri:dev

# Standard production build

npm run tauri:build

# Linux build with native DuckDB for better performance

npm run tauri:build:native-duckdb

# Mac App Store submission build

npm run tauri:build:mas

# Build for specific targets only

npm run tauri:build -- --target aarch64-apple-darwin

```

## Key Files Reference

| File | Purpose |
|------|---------|
| [`apps/geolibre-desktop/package.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/package.json) | Workspace entry and npm script definitions |
| `scripts/tauri-build.mjs` | Build orchestration and feature flag handling |
| [`apps/geolibre-desktop/src-tauri/tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.conf.json) | Primary Tauri configuration |
| [`apps/geolibre-desktop/src-tauri/tauri.mas.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/tauri.mas.conf.json) | Mac App Store variant configuration |
| [`apps/geolibre-desktop/src-tauri/src/main.rs`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src-tauri/src/main.rs) | Rust application entry point |
| `backend/geolibre_server/` | Python FastAPI sidecar for geoprocessing |

## Summary

- **Tauri v2 desktop build** in GeoLibre operates within a standard **npm workspaces monorepo**, with the desktop app isolated at `apps/geolibre-desktop`
- **Custom build script** at `scripts/tauri-build.mjs` handles feature flags (`--native-duckdb`, `--mas`) and spawns the Tauri CLI with correct arguments
- **Cargo features** toggle between WebAssembly and native DuckDB engines, and between standard and Mac App Store compliance modes
- **Vite integration** provides fast development workflows and optimized production bundles embedded in the native binary
- **Python sidecar** extends desktop capabilities with FastAPI-based geoprocessing, excluded from MAS builds per platform policy

## Frequently Asked Questions

### What is the purpose of `scripts/tauri-build.mjs` in the GeoLibre Tauri v2 desktop build?

The script `scripts/tauri-build.mjs` serves as the build orchestrator for GeoLibre's Tauri v2 desktop application. It parses command-line flags like `--native-duckdb` and `--mas`, injects corresponding Cargo features and environment variables, adds platform-specific defaults (such as `--bundles deb,rpm` on Linux), and spawns the Tauri CLI through npm workspaces with all assembled arguments.

### How does the native DuckDB feature improve performance in GeoLibre desktop builds?

The `--native-duckdb` flag enables the `native-duckdb` Cargo feature, which replaces the WebAssembly DuckDB implementation with a native binary linked at compile time. This eliminates WASM runtime overhead and memory constraints, delivering faster query execution for large vector and raster geospatial operations at the cost of increased binary size and platform-specific dependencies.

### Why does the Mac App Store build disable the Python sidecar?

Apple's Mac App Store sandboxing policy prohibits applications from spawning external processes or executing arbitrary code. The GeoLibre build system detects the `--mas` flag, switches to [`tauri.mas.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.mas.conf.json), and sets `GEOLIBRE_MAS_BUILD=1` to exclude the Python sidecar, Jupyter integration, and automatic updater — components that would violate these policies and prevent App Store approval.

### Can I add custom Cargo features to the GeoLibre Tauri build?

Yes. The `scripts/tauri-build.mjs` file uses standard Node.js argument parsing that you can extend to recognize additional flags. Add your feature detection logic alongside the existing `--native-duckdb` and `--mas` handlers, then append your feature to the `cargoFeatures` array before the Tauri CLI spawn call. Alternatively, create a new npm script that forwards raw arguments directly to `npm run tauri -- build`.