# How Tauri v2 Provides Native Filesystem Access for MBTiles and Rasters

> Discover how Tauri v2 unlocks native filesystem access for MBTiles and rasters. Learn about its I/O abstraction layer bridging JS web APIs with platform-native dialogs and binary operations for efficient geospatial data handling.

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

---

**Tauri v2 enables native filesystem access for MBTiles and raster data through a unified I/O abstraction layer that bridges JavaScript web APIs with platform-native file dialogs and binary read/write operations.**

The **GeoLibre** project uses **Tauri v2** to give its web-based geospatial interface direct, high-performance access to large local files—MBTiles archives, GeoTIFFs, and other raster formats—without sacrificing the security sandbox of the Chromium webview. This article breaks down exactly how the implementation works, with references to the actual source code in `opengeos/GeoLibre`.

---

## Runtime Detection: Knowing When You're in Tauri

Before any filesystem call, the application must determine whether it's running as a Tauri desktop app or a standard browser instance. This check happens in two places:

- **[`src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/src/lib.rs)** – The Rust side exports a simple `is_tauri` command that always returns `true` when the Tauri runtime is active.
- **[`apps/geolibre-desktop/src/lib/is-tauri.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/is-tauri.ts)** – A thin TypeScript wrapper that invokes this command via `@tauri-apps/api/core`, caching the result for synchronous checks throughout the UI.

Components import `isTauri` from this module to branch between native and web code paths:

```typescript
import { isTauri } from '../../lib/is-tauri';

if (isTauri) {
  // Use Tauri's native file dialogs and FS APIs
} else {
  // Fall back to browser File System Access API
}

```

---

## The Unified I/O Layer: [`tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/tauri-io.ts)

All filesystem operations in GeoLibre flow through **[`apps/geolibre-desktop/src/lib/tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/tauri-io.ts)**. This module provides **isomorphic functions** that work identically whether the app runs in Tauri or the browser.

The abstraction handles three core operations:

1. **Opening files** with `openLocalDataFileWithFallback`
2. **Saving binary data** with `saveBinaryFileWithFallback`
3. **Saving text data** with `saveTextFileWithFallback`

### Opening MBTiles and Raster Files

When a user imports local data, the UI calls `openLocalDataFileWithFallback`. Under Tauri, this function:

- Invokes `@tauri-apps/plugin-dialog` for a native file picker
- Reads the selected file with `@tauri-apps/plugin-fs` `readBinaryFile`
- Returns the bytes as a `Uint8Array`

In browser mode, it uses `window.showOpenFilePicker` and `File.arrayBuffer()` instead.

```typescript
import { openLocalDataFileWithFallback } from '../../lib/tauri-io';

async function loadMbtiles() {
  const { data, fileName } = await openLocalDataFileWithFallback({
    filters: [{ name: 'MBTiles', extensions: ['mbtiles'] }],
  });
  // data is Uint8Array — ready for DuckDB-WASM or direct parsing
  await addMbtilesLayer({ bytes: data, name: fileName });
}

```

### Saving Processed Outputs

Export functions use `saveBinaryFileWithFallback` to write generated rasters or MBTiles back to disk. The Tauri path calls `writeBinaryFile` from `@tauri-apps/plugin-fs`, while the browser path uses `FileSystemWritableFileStream`.

```typescript
import { saveBinaryFileWithFallback } from '../../lib/tauri-io';

async function exportGeotiff(rasterBytes: Uint8Array) {
  await saveBinaryFileWithFallback({
    defaultFileName: 'export.tif',
    data: rasterBytes,
  });
}

```

---

## Security Scoping and Path Restrictions

Tauri v2's filesystem access is **not unrestricted**. The **[`src-tauri/tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/tauri.conf.json)** configuration defines a whitelist of accessible directories—typically the app-specific resource directory and user-selected paths from dialog interactions.

The Rust side in **[`src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/src/lib.rs)** enforces this boundary. File operations outside the allowed scope are rejected at the native layer before reaching the host OS.

---

## Custom Protocol for MapLibre Integration

GeoLibre registers a **`tauri:` URI scheme** to stream local MBTiles data directly into MapLibre GL. This allows the map engine to treat local files like remote tile sources without copying data into memory.

The protocol handler is registered in [`src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/src/lib.rs):

```rust
fn register_tauri_protocol(app: &mut tauri::App) {
  app.handle()
     .register_uri_scheme_protocol("tauri", move |_app, request| {
        // Parse the MBTiles path from request.uri()
        // Read from the whitelisted resource directory
        // Stream bytes back as a tile response
     });
}

```

When MapLibre requests a tile, the protocol handler queries the local MBTiles SQLite database, extracts the relevant blob, and returns it with proper HTTP headers. This **zero-copy streaming** avoids loading entire archives into the JavaScript heap.

---

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/src/lib.rs) | Rust runtime: `is_tauri` command, protocol registration, path validation |
| [`apps/geolibre-desktop/src/lib/tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/tauri-io.ts) | Unified JavaScript I/O abstraction for Tauri and browser environments |
| [`apps/geolibre-desktop/src/lib/is-tauri.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/is-tauri.ts) | Runtime detection helper with cached `isTauri` flag |
| [`apps/geolibre-desktop/src/components/layout/add-data/sources/MbtilesSource.tsx`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/layout/add-data/sources/MbtilesSource.tsx) | UI component for MBTiles import via `openLocalDataFileWithFallback` |
| [`apps/geolibre-desktop/src/components/processing/ConversionDialog.tsx`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/processing/ConversionDialog.tsx) | Raster export UI using `saveBinaryFileWithFallback` |

---

## Summary

- **Runtime detection** via [`is-tauri.ts`](https://github.com/opengeos/GeoLibre/blob/main/is-tauri.ts) enables conditional use of native vs. web APIs
- **[`tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/tauri-io.ts)** provides a single abstraction for file open/save operations across environments
- **Tauri v2 plugins** (`@tauri-apps/plugin-fs`, `@tauri-apps/plugin-dialog`) handle native binary I/O
- **Security whitelisting** in [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) and Rust-side validation restrict filesystem scope
- **Custom `tauri:` protocol** streams MBTiles directly to MapLibre without memory copies

---

## Frequently Asked Questions

### What Tauri v2 plugins does GeoLibre use for filesystem access?

GeoLibre uses `@tauri-apps/plugin-fs` for binary file read/write operations and `@tauri-apps/plugin-dialog` for native file picker dialogs. These replace the older Tauri v1 `fs` and `dialog` modules with a more modular architecture. The plugins are declared in [`src-tauri/Cargo.toml`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/Cargo.toml) and initialized in [`src-tauri/src/lib.rs`](https://github.com/opengeos/GeoLibre/blob/main/src-tauri/src/lib.rs) before the application starts.

### Can the same code run in both Tauri desktop and standard browsers?

Yes. The [`tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/tauri-io.ts) module implements fallback logic for every filesystem operation. When `isTauri` is false, it uses the File System Access API (`showOpenFilePicker`, `showSaveFilePicker`, `FileSystemWritableFileStream`) to provide equivalent functionality in modern browsers. This lets GeoLibre maintain a single codebase for web and desktop deployments.

### How does Tauri v2 prevent unauthorized filesystem access?

Tauri v2 enforces a **capability-based security model**. The [`tauri.conf.json`](https://github.com/opengeos/GeoLibre/blob/main/tauri.conf.json) defines explicit permissions for which directories and operations are allowed. The Rust runtime validates every path against this whitelist before executing filesystem calls. Additionally, the `tauri:` protocol handler only serves files from the configured resource directory, preventing directory traversal attacks from the webview.