# What Are the Key State Modules in GeoLibre's Zustand Store?

> Explore GeoLibre's Zustand store, featuring ten key state modules for managing project data, map views, layers, and collaboration in your geospatial applications.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: internals
- Published: 2026-07-31

---

**GeoLibre organizes its application state into ten distinct modules within a centralized Zustand store located at [`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts), covering everything from project metadata and map views to layer management and real-time collaboration.**

The open-source **GeoLibre** project (opengeos/GeoLibre) manages complex GIS application state using a single, undo-aware Zustand store. Understanding these key state modules is essential for developers building plugins, custom UI components, or integrations with the core mapping library.

## Project and Metadata State

The **Project & Metadata** module handles application-level persistence and file operations. Defined in [`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts) around lines 81-106, this slice tracks `projectName`, `projectPath`, `projectGeneration`, and `isDirty` flags.

Key actions include `newProject`, `loadProject`, `setProjectName`, and `markSaved`. The module also maintains `recentProjects` for quick access to previously opened files and `attributeFilter` for table-level filtering across vector data.

## Map View and Basemap Configuration

The **Map View & Basemap** module controls the camera and background imagery state. Located at lines 84-92 in [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts), it stores `mapView` (center, zoom, bearing), `basemapStyleUrl`, `basemapVisible`, and `basemapOpacity`.

Available actions include `setMapView`, `setBasemapStyleUrl`, and specialized planetary mapping functions: `applyPlanetaryBasemap` and `restoreEarthBasemap`. This separation allows the application to switch between Earth and extraterrestrial projections while maintaining independent view states.

## Layer and Group Management

The **Layers & Groups** module forms the data backbone of the application. Spanning lines 88-104 in [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts), this slice maintains `layers`, `layerGroups`, `layerLibrary`, `styleLibrary`, `projectStyleLibrary`, and `templateLibrary`.

Actions follow CRUD patterns with `addLayer`, `removeLayer`, `updateLayer`, and `setLayerVisibility`. Group operations include `addLayerGroup`, `removeLayerGroup`, and `moveLayerToGroup`. Style persistence is handled through `saveStyleLibraryEntry`, allowing reusable symbology across projects.

## Advanced Map Layout and Selection

### Multi-Pane Grid State

The **Map Grid & Multi-Pane** module enables multi-viewport comparisons at lines 124-138. It stores `mapLayout` (grid configuration), `secondaryMapViews` (additional viewports), and `primaryMapLabel`.

Actions like `setMapGrid`, `setSyncView`, `setSecondaryMapView`, and `removeSecondaryMapView` allow synchronized or independent navigation across multiple map panes, useful for side-by-side historical imagery comparisons or multi-scale analysis.

### Selection and Identify Operations

The **Selection & Identify** module at lines 138-147 manages interactive query state through `selectedLayerId`, `selectedFeatureId`, `selectedFeatureIds`, `identifyLayerId`, and `pointerCoords`.

Actions include `selectLayer`, `selectFeature`, `selectFeatures`, `setIdentifyLayer`, and `setPointerCoords`. This module bridges the gap between raw map interactions and the application's attribute table and info panels.

## UI State and Collaboration

### UI Visibility Flags

The **UI Visibility** module (lines 180-210) consolidates hundreds of boolean flags into a `ui` sub-object. Properties include `processingOpen`, `conversionOpen`, `vectorToolOpen`, `dashboardOpen`, and `storymapPanelOpen`.

Rather than scattered component state, these are controlled through actions like `setProcessingOpen`, `setConversionOpen`, and `setDashboardOpen`, enabling cross-component coordination and restoration of complex workspace layouts.

### Real-Time Collaboration

The **Collaboration** slice at lines 196-210 handles live session state including participant presence, chat history, and session metadata. State properties live within a `collaboration` sub-object.

Actions include `setCollaboration`, `updateCollaborationPresence`, `addCollaborationChat`, and `resetCollaboration`. This module integrates with WebRTC or WebSocket backends to provide multi-user editing capabilities without conflicting with local undo history.

## Specialized Workflows

### Processing and Model History

The **Processing History & Models** module tracks geoprocessing operations and ML models at lines 190-201. It stores `processingHistory`, `models`, `widgets`, and `dashboardColumns`.

Actions like `addProcessingRun`, `clearProcessingHistory`, `saveModel`, and `setDashboardColumns` enable audit trails of spatial analyses and persistent widget configurations for data dashboards.

### Story Map State

The **Story Map** module (overlapping lines 190-200) maintains narrative configuration through `storymap` properties and related UI flags.

Actions include `setStorymap`, `addStoryChapter`, and `setStorymapPanelOpen`, allowing authors to construct scroll-driven or slide-based geospatial narratives while maintaining the underlying map view state.

### GPS Status

The **GPS Status** slice (lines 150-152) provides a minimal, focused state for mobile and field data collection through the `gpsStatus` property.

Updated via `setGpsStatus`, this feeds real-time location fixes into the status bar and geolocation-based tools without triggering unnecessary re-renders of the full map component.

## Accessing the Store in Practice

The store is exposed through the **`useAppStore`** hook created with Zustand and the `temporal` middleware from `zundo` for undo/redo support:

```typescript
// packages/core/src/store.ts
export const useAppStore = create<AppState>()(
  temporal(
    (set, get) => ({
      // …initial state & actions
    })
  )
);

```

### Reading State

Access specific slices to prevent unnecessary re-renders:

```typescript
import { useAppStore } from "@geolibre/core";

const basemapUrl = useAppStore((s) => s.basemapStyleUrl);
const selectedLayer = useAppStore((s) => s.selectedLayerId);

```

### Updating Map View

Programmatically control the camera and mark the project as modified:

```typescript
useAppStore.getState().setMapView(
  { center: [12.49, 41.89], zoom: 12 },
  true   // markDirty = true
);

```

### Adding Vector Layers

Import GeoJSON programmatically from plugins or custom handlers:

```typescript
import type { FeatureCollection } from "geojson";

const layerId = useAppStore.getState().addGeoJsonLayer(
  "My GeoJSON",
  myFeatureCollection as FeatureCollection,
  "/path/to/source.geojson"
);

```

### Managing Layer Groups

Organize data hierarchically:

```typescript
const groupId = useAppStore.getState().addLayerGroup("My Group");
useAppStore.getState().moveLayerToGroup(layerId, groupId);

```

## Related State Management Files

Beyond [`store.ts`](https://github.com/opengeos/GeoLibre/blob/main/store.ts), the state architecture relies on several supporting modules:

- **[`packages/core/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/types.ts)** – TypeScript definitions for `AppState`, `GeoLibreLayer`, `LayerGroup`, and `MapViewState`
- **[`packages/core/src/history.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/history.ts)** – Undo/redo utilities using the `temporal` middleware with coalescing and trimming logic
- **[`packages/core/src/project.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/project.ts)** – Project serialization/deserialization helpers that hydrate the store via `loadProject`
- **[`packages/core/src/layer-defaults.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/layer-defaults.ts)** – Default symbology applied when `addLayer` creates new entries
- **[`packages/core/src/joins.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/joins.ts)** – Attribute join logic consumed by layer update actions

## Summary

- GeoLibre's state resides in a single Zustand store at [`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts) with undo capabilities via `zundo`
- **Ten distinct modules** separate concerns: Project Metadata, Map View, Layers/Groups, Grid Layout, Selection, UI Flags, Collaboration, Processing History, Story Maps, and GPS
- Each module exposes **typed actions** that update specific slices while maintaining immutability of unrelated state
- The **`useAppStore`** hook supports selector optimization and direct state access via `getState()`
- Supporting files in `packages/core/src/` handle persistence, history management, and default styling

## Frequently Asked Questions

### How does GeoLibre handle undo/redo with Zustand?

GeoLibre wraps the store creator with the `temporal` middleware from `zundo` (as seen in [`packages/core/src/store.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/store.ts) and [`history.ts`](https://github.com/opengeos/GeoLibre/blob/main/history.ts)). This tracks state changes over time and provides undo/redo functionality without manual history management. Actions that update the store automatically generate history entries, while the [`history.ts`](https://github.com/opengeos/GeoLibre/blob/main/history.ts) utilities handle coalescing rapid changes and trimming the history buffer to manage memory.

### Can I subscribe to only specific state modules to optimize performance?

Yes. The `useAppStore` hook accepts selector functions, allowing components to subscribe to individual properties (e.g., `useAppStore((s) => s.basemapStyleUrl)`). This ensures components re-render only when their specific slice changes, even though all modules live in the same centralized store. The Zustand architecture handles efficient diffing and notification automatically.

### Where are the TypeScript types for the state modules defined?

All type definitions reside in [`packages/core/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/core/src/types.ts). This includes the monolithic `AppState` interface that aggregates all modules, as well as supporting types like `GeoLibreLayer`, `MapViewState`, `LayerGroup`, and the `Collaboration` slice interfaces. The store file imports these types to ensure the Zustand state shape remains strictly typed throughout the application.

### How does the Collaboration module synchronize between users?

The Collaboration module (lines 196-210) stores presence and chat data locally, but it relies on external transport layers (WebSockets or WebRTC) managed outside the core store. Actions like `updateCollaborationPresence` and `addCollaborationChat` update local state when remote messages arrive. The store itself remains transport-agnostic, focusing purely on state management while the application layer handles real-time synchronization protocols.