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 simpleis_tauricommand that always returnstruewhen 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:
- Opening files with
openLocalDataFileWithFallback - Saving binary data with
saveBinaryFileWithFallback - 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-dialogfor a native file picker - Reads the selected file with
@tauri-apps/plugin-fsreadBinaryFile - 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.tsenables conditional use of native vs. web APIs tauri-io.tsprovides 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.jsonand 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →