How Tauri v2 Provides Native Filesystem Access for MBTiles and Rasters

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 – 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 – 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:

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

All filesystem operations in GeoLibre flow through 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.

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.

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

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 Rust runtime: is_tauri command, protocol registration, path validation
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 Runtime detection helper with cached isTauri flag
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 Raster export UI using saveBinaryFileWithFallback

Summary

  • Runtime detection via is-tauri.ts enables conditional use of native vs. web APIs
  • 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 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 and initialized in 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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →