# Best Practices for Listing Files in GeoLibre: 5 Proven Methods for Desktop and Web

> Master GeoLibre file listing with 5 proven desktop and web methods. Optimize your data management with Tauri dialogs, drag-and-drop, and more.

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

---

**GeoLibre unifies five distinct file-listing strategies—Tauri native dialogs, HTML file inputs, drag-and-drop, remote catalogs, and plugin extensions—into a single `addLayer` pipeline that produces consistent `GeoLibreLayer` records in the central store.**

Whether you're building a desktop geospatial application or deploying to the browser, understanding how GeoLibre lists and imports files is essential for extending its data pipeline. Each approach follows a dedicated code path but ultimately converges on the same store mutation in `@geolibre/core`, ensuring consistent layer handling regardless of source.

## Understanding the Core Architecture

All file-listing methods in GeoLibre share a unified destination. When a user selects files through any supported mechanism, the resulting data flows through loaders like **DuckDB-WASM** (`ST_Read`) or **shpjs**, then enters the central store via `addGeoJsonLayer` or equivalent helpers.

This design means you can mix local files, remote URLs, and plugin-provided listings within the same project without duplicating import logic.

## Method 1: Native File-System Dialogs (Tauri Desktop)

For desktop builds, GeoLibre leverages **Tauri's native dialog API** to provide system-native file browsing with full filesystem access.

The implementation lives in [`apps/geolibre-desktop/src/hooks/useAddData.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/hooks/useAddData.ts), where `window.__TAURI__.dialog.open` returns absolute filesystem paths:

```typescript
// apps/geolibre-desktop/src/hooks/useAddData.ts
export async function openFileDialog() {
  const files = await window.__TAURI__.dialog.open({
    multiple: true,
    filters: [{ name: 'Geo files', extensions: ['geojson', 'shp', 'zip', 'kml'] }],
  });
  if (!files) return;
  // `files` is an array of absolute paths
  for (const path of files) {
    await addGeoJsonLayerFromPath(path);
  }
}

```

**Key characteristics:**
- Returns **absolute paths** that bypass browser sandboxing
- Supports **multi-select** and **extension filtering**
- Paths feed directly to DuckDB-WASM or specialized loaders

Unique layer IDs are generated via [`packages/map/src/vector-tile-layer-ids.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/map/src/vector-tile-layer-ids.ts) before store insertion.

## Method 2: HTML `<input type="file">` (Web Build)

Browser deployments use standard **HTML5 file inputs** with identical filtering capabilities. The `FileList` object provides `File` instances read via `FileReader` or streamed to DuckDB-WASM.

From [`apps/geolibre-desktop/src/components/AddDataDialog.tsx`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/AddDataDialog.tsx):

```tsx
// apps/geolibre-desktop/src/components/AddDataDialog.tsx
<input
  type="file"
  multiple
  accept=".geojson,.shp,.zip,.kml"
  onChange={e => {
    const list = e.target.files;
    if (list) {
      Array.from(list).forEach(file => addGeoJsonLayerFromFile(file));
    }
  }}
/>

```

The resulting GeoJSON passes through [`packages/map/src/style-mapper.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/map/src/style-mapper.ts) to generate MapLibre-compatible sources and layers. Both desktop and web builds share the same downstream pipeline—only the acquisition mechanism differs.

## Method 3: Drag-and-Drop Integration

GeoLibre treats **drag-and-drop** as a first-class input method. The `DataTransfer` object from drop events yields a `FileList` identical to file inputs, enabling code reuse.

Implementation in [`apps/geolibre-desktop/src/components/MapCanvas.tsx`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/MapCanvas.tsx) sets `onDrop` handlers that extract files and forward them to the standard import pipeline. For **ZIP shapefiles**, specialized handling in [`packages/processing/src/wasm-convert.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/wasm-convert.ts) decompresses and converts before layer creation.

This method is particularly valuable for rapid iteration—users can drag files directly onto the map canvas or sidebar without navigating dialogs.

## Method 4: Remote File Browsing (Source Cooperative, Hugging Face)

Remote datasets require **virtual file listings** rather than filesystem access. GeoLibre's remote panel architecture fetches JSON catalogs and presents them as browseable interfaces.

The format support and constraints are defined in [`packages/plugins/src/plugins/remote-file-formats.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/plugins/remote-file-formats.ts):

```tsx
// packages/plugins/src/plugins/remote-file-panels.tsx
{remoteCatalog.map(item => (
  <button key={item.id} onClick={() => addRemoteLayer(item.url, item.name)}>
    {item.name}
  </button>
))}

```

Selection triggers **HTTP-streamed imports** via DuckDB-WASM's `ST_Read` over HTTP, treating remote URLs similarly to local paths. This enables direct integration with **Source Cooperative**, **Hugging Face datasets**, and other cloud-hosted geospatial repositories.

## Method 5: Plugin-Provided File Listings

GeoLibre's extensibility allows **plugins to register custom file listers** through a standardized API. Plugins expose arrays of file descriptors that the core UI consumes and renders.

Registration occurs via [`packages/plugins/src/plugins/plugin-api.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/plugins/plugin-api.ts):

```typescript
// packages/plugins/src/plugins/plugin-api.ts
registerFileLister(sourceId: string, lister: FileLister): void;

```

The `usePlugins` hook in [`apps/geolibre-desktop/src/hooks/usePlugins.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/hooks/usePlugins.ts) aggregates all registered listers and merges them into the **Add Data dialog**. This pattern enables cloud storage providers, database connectors, and proprietary formats to surface their contents without modifying core code.

## The Unified Store Pipeline

Despite five distinct entry points, all paths converge on the same **Zustand store mutation**:

```typescript
// Central store mutation (simplified)
import { useStore } from '@geolibre/core';

export function addGeoJsonLayer(data: GeoJSON.GeoJSON, name: string) {
  const id = generateLayerId();
  useStore.getState().addLayer({
    id,
    name,
    type: 'geojson',
    source: { type: 'geojson', data },
    // …additional UI metadata
  });
}

```

The store definition in [`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts) holds the `layers` array and provides `addLayer`. MapLibre synchronization happens automatically through `@geolibre/map` subscriptions.

## Implementation Best Practices

**Choose methods based on deployment target:**
- **Desktop-only features** → Prioritize Tauri dialogs for native UX
- **Cross-platform needs** → Implement both Tauri and HTML input branches
- **Cloud-first workflows** → Lead with remote panels and plugin extensions

**Maintain loader compatibility:**
- Verify DuckDB-WASM `ST_Read` supports your target formats
- Use [`packages/processing/src/wasm-convert.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/processing/src/wasm-convert.ts) helpers for legacy formats like Shapefile-in-ZIP

**Preserve layer ID uniqueness:**
- Always route through [`vector-tile-layer-ids.ts`](https://github.com/opengeos/GeoLibre/blob/main/vector-tile-layer-ids.ts) generators to prevent collision

## Summary

- **Five listing methods** cover desktop, web, drag-and-drop, remote catalogs, and plugin extensions—all converging on unified store mutations
- **Tauri native dialogs** provide absolute path access with system-native UX in [`useAddData.ts`](https://github.com/opengeos/GeoLibre/blob/main/useAddData.ts)
- **HTML file inputs** enable identical web deployment through `FileReader` or streaming
- **Drag-and-drop** reuses file-input pipeline via `DataTransfer` in [`MapCanvas.tsx`](https://github.com/opengeos/GeoLibre/blob/main/MapCanvas.tsx)
- **Remote panels** stream HTTP sources through DuckDB-WASM using format definitions in [`remote-file-formats.ts`](https://github.com/opengeos/GeoLibre/blob/main/remote-file-formats.ts)
- **Plugin listers** extend the Add Data dialog without core modifications via `registerFileLister`

## Frequently Asked Questions

### What file formats does GeoLibre support for listing and import?

GeoLibre supports **GeoJSON, Shapefile (including ZIP archives), KML, and additional vector formats** through DuckDB-WASM's `ST_Read`. The specific extensions are defined in [`remote-file-formats.ts`](https://github.com/opengeos/GeoLibre/blob/main/remote-file-formats.ts) and dialog filter configurations. For web builds, format support depends on DuckDB-WASM capabilities and any additional WASM converters loaded.

### Can I add custom remote data sources to the file listing?

Yes. Implement a plugin using the **`registerFileLister` API** in [`packages/plugins/src/plugins/plugin-api.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/plugins/plugin-api.ts). Your plugin returns file descriptors that the core UI renders automatically. This pattern powers the built-in Source Cooperative and Hugging Face integrations and supports any HTTP-accessible geospatial catalog.

### How does GeoLibre handle large file listings without performance degradation?

Remote panels use **virtualized lists** for catalog browsing, and the store maintains layers by reference rather than deep copies. For actual data loading, DuckDB-WASM supports **streaming reads** over HTTP, avoiding full materialization until visualization requires it. The layer ID generation in [`vector-tile-layer-ids.ts`](https://github.com/opengeos/GeoLibre/blob/main/vector-tile-layer-ids.ts) remains constant-time regardless of catalog size.