# How to List Specific File Types in GeoLibre: A Complete Developer Guide

> Learn how to list specific file types in GeoLibre with filterSupportedFiles. This guide provides granular control for vector, raster, or project files.

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

---

**Use `filterSupportedFiles()` from `@geolibre/ui/file-names` to whitelist extensions, then apply custom Set-based filters for granular control over vector, raster, or project-specific file lists.**

GeoLibre is an open-source, multi-platform geospatial workbench built on a monorepo architecture with npm workspaces (`apps/*`, `packages/*`, `workers/*`) and a Python FastAPI side-car. Listing specific file types is a core requirement when building custom import dialogs, batch processors, or plugins that handle geospatial data. The platform provides centralized file-type utilities that ensure consistent behavior across desktop (Tauri), web, and embedded environments.

## Core File-Type Filtering Architecture

GeoLibre's file-type handling lives in the desktop application's I/O layer, specifically in [`apps/geolibre-desktop/src/lib/file-names.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/file-names.ts). This module exports the foundational utilities that the entire codebase uses to validate and categorize files.

### Primary Filtering Functions

The main entry point for file-type operations is **`filterSupportedFiles(files: File[]): File[]`**, which returns only files whose extensions match GeoLibre's internal whitelist. This whitelist excludes non-geospatial formats, system files (like macOS `__MACOSX` entries), and metadata files by default.

For extension extraction, the codebase uses **`extOf(file)`**, a lightweight utility that returns the lower-cased extension from a `File` object. This normalization ensures case-insensitive matching across operating systems.

### Extension Categories in GeoLibre

GeoLibre internally groups supported extensions by data category:

- **Vector**: `.shp`, `.geojson`, `.parquet`, `.kml`, `.gml`
- **Raster**: `.tif`, `.png`, `.jpg`, `.mbtiles`
- **Project/Config**: Varies by plugin (filtered by default in most contexts)

## Listing Specific File Types: Implementation Patterns

### Pattern 1: Filter by Raster Format Only

To display only raster imagery in a custom "Add Raster Layer" dialog:

```typescript
import { filterSupportedFiles, extOf } from '@geolibre/ui/file-names';

const rasterExts = new Set(['.tif', '.png', '.jpg', '.mbtiles']);

function listRasterFiles(files: File[]): File[] {
  const supported = filterSupportedFiles(files);
  return supported.filter(f => rasterExts.has(extOf(f).toLowerCase()));
}

```

### Pattern 2: Isolate Shapefile Components

ESRI Shapefiles require multiple companion files. The filtering logic in [`tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/tauri-io.ts) demonstrates how to collect all parts of a Shapefile dataset:

```typescript
import { filterSupportedFiles, extOf } from '@geolibre/ui/file-names';

// `selected` comes from a file-picker dialog
const supported = filterSupportedFiles(selected);

// Keep only Shapefile parts using explicit extension list
const shpParts = supported.filter(f =>
  ['.shp', '.shx', '.dbf', '.prj', '.cpg'].includes(extOf(f).toLowerCase())
);

console.log('Shapefile parts to load:', shpParts.map(f => f.name));

```

The **desktop-specific routine** in [`apps/geolibre-desktop/src/lib/tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/tauri-io.ts) extends this pattern—it reads a chosen `.shp` file and automatically discovers its side-car files from the same directory, filtering unsupported entries before integration into the Zustand store.

### Pattern 3: Custom Category Filter with Multiple Sets

For plugins that need dynamic category selection:

```typescript
import { filterSupportedFiles, extOf } from '@geolibre/ui/file-names';

type FileCategory = 'vector' | 'raster' | 'project';

const extensionMap: Record<FileCategory, Set<string>> = {
  vector: new Set(['.shp', '.geojson', '.parquet', '.kml', '.gml']),
  raster: new Set(['.tif', '.png', '.jpg', '.mbtiles', '.webp']),
  project: new Set(['.geolib', '.json'])
};

function listFilesByCategory(
  files: File[], 
  category: FileCategory
): File[] {
  const supported = filterSupportedFiles(files);
  const targetExts = extensionMap[category];
  return supported.filter(f => targetExts.has(extOf(f).toLowerCase()));
}

```

## Key Source Files and Their Roles

| File | Path | Responsibility |
|------|------|--------------|
| [`file-names.ts`](https://github.com/opengeos/GeoLibre/blob/main/file-names.ts) | [`apps/geolibre-desktop/src/lib/file-names.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/file-names.ts) | Extension extraction (`extOf`), generic whitelist filtering (`filterSupportedFiles`), display name mapping |
| [`tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/tauri-io.ts) | [`apps/geolibre-desktop/src/lib/tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/tauri-io.ts) | Desktop file reading, Shapefile side-car discovery, platform-specific filtering |
| [`types.ts`](https://github.com/opengeos/GeoLibre/blob/main/types.ts) | [`packages/plugins/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/types.ts) | `VectorFile` type definition documenting primary files and companions |
| [`maplibre-vector.ts`](https://github.com/opengeos/GeoLibre/blob/main/maplibre-vector.ts) | [`packages/plugins/src/plugins/maplibre-vector.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/plugins/maplibre-vector.ts) | Vector plugin integrating filtered files into MapLibre rendering |

## Summary

- **Centralized filtering** through `filterSupportedFiles()` in [`file-names.ts`](https://github.com/opengeos/GeoLibre/blob/main/file-names.ts) ensures consistent behavior across all GeoLibre hosts.
- **Extension-based granularity** using `extOf()` and custom `Set` filters enables precise control over vector, raster, or specialized format lists.
- **Shapefile handling** requires explicit multi-extension filtering to capture `.shp`, `.shx`, `.dbf`, `.prj`, and `.cpg` components.
- **Cross-platform parity** is maintained because the same utilities power the desktop UI, web UI, and Jupyter embedded environments.

## Frequently Asked Questions

### How does GeoLibre handle case-insensitive file extensions?

GeoLibre normalizes all extensions to lowercase using `extOf()`, which is implemented in [`apps/geolibre-desktop/src/lib/file-names.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/lib/file-names.ts). This ensures `.TIF`, `.Tif`, and `.tif` are treated identically regardless of the source operating system.

### Can I add custom file types to the whitelist?

Yes. While `filterSupportedFiles()` uses an internal whitelist, you can bypass it and implement custom validation by using `extOf()` directly. For plugin-wide changes, extend the type definitions in [`packages/plugins/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/types.ts) and register your extensions with the core store.

### Why does GeoLibre filter out `__MACOSX` directories automatically?

The [`tauri-io.ts`](https://github.com/opengeos/GeoLibre/blob/main/tauri-io.ts) module explicitly excludes macOS resource fork directories and other meta-files during the file discovery phase. This prevents system-generated content from polluting the layer list when users import data from Apple-compressed archives.

### Does the web version use the same file-type utilities?

Yes. The `@geolibre/ui/file-names` package is shared across environments. The web UI imports the same `filterSupportedFiles` and `extOf` functions, ensuring identical filtering logic whether running in Tauri desktop or a browser context.