# How GeoLibre Plugins Work and How They Are Registered: A Deep Dive into the Architecture

> Discover how GeoLibre plugins work and get registered. Explore the dynamic module discovery system and Plugin Manager architecture in opengeos/GeoLibre.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: deep-dive
- Published: 2026-08-01

---

**GeoLibre plugins work through a dynamic module discovery system in the `packages/plugins` workspace, where each plugin exports a `PluginDefinition` object that the Plugin Manager automatically aggregates and registers into specialized UI registries for toolbars, side panels, and floating windows.**

GeoLibre, an open-source geospatial platform maintained by the opengeos/GeoLibre repository, provides a modular plugin architecture that allows developers to extend functionality without modifying core application code. Understanding how GeoLibre plugins are discovered and registered is essential for customizing the desktop application or integrating new geospatial capabilities. The system leverages TypeScript interfaces, wildcard module imports, and a centralized state management pattern to seamlessly inject new features into the user interface.

## The PluginDefinition Interface

Every GeoLibre plugin must implement the **`PluginDefinition`** interface located in [`packages/plugins/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/types.ts). This contract mandates specific metadata fields and optional factory functions that determine how the plugin integrates with the application.

The interface requires:

- **`id`**: A unique string identifier for the plugin
- **`title`**: The display name shown in UI menus
- **`icon`**: An emoji or icon string for visual identification
- **`ToolbarComponent`**: Optional React component for toolbar integration
- **`RightPanelComponent`**: Optional React component for side panel rendering
- **`createLayer`**: Optional function to instantiate map layers

## How the Plugin Manager Discovers Plugins

The **Plugin Manager** ([`packages/plugins/src/plugin-manager.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/plugin-manager.ts)) orchestrates the automatic discovery process. Rather than requiring manual imports, the manager uses a wildcard import statement (`import * as plugins from './plugins'`) to dynamically load every module placed in the `packages/plugins/src/plugins/` directory.

During initialization, the manager iterates through these modules and constructs a **`pluginsById`** map, keyed by each plugin's unique identifier. This aggregation happens automatically at build time, meaning any new file added to the plugins directory is immediately eligible for registration without updating import statements.

## The Three Registry Types

Once aggregated, the Plugin Manager distributes plugin definitions to three specialized registries that handle different UI contexts:

**Toolbar Menu Registry** ([`packages/plugins/src/toolbar-menu-registry.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/toolbar-menu-registry.ts)): Manages plugins that add buttons or controls to the top toolbar. It exposes the `useToolbarMenu` hook for React components to access registered toolbar items.

**Right-Panel Registry** ([`packages/plugins/src/right-panel-registry.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/right-panel-registry.ts)): Handles plugins appearing in the right-hand side panel, such as layer controls or time-slider settings. This registry provides the `useRightPanel` hook for component rendering.

**Floating-Panel Registry** ([`packages/plugins/src/floating-panel-registry.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/floating-panel-registry.ts)): Registers plugins that create floating dialog windows, including "Add Data" or processing tool dialogs. Access these through the `useFloatingPanel` hook.

Each registry filters the master plugin map based on which UI components the plugin defines, ensuring efficient rendering of only relevant interface elements.

## UI Integration and State Management

The desktop application initializes the entire plugin system through the **[`usePlugins.ts`](https://github.com/opengeos/GeoLibre/blob/main/usePlugins.ts)** hook located at [`apps/geolibre-desktop/src/hooks/usePlugins.ts`](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/hooks/usePlugins.ts). This hook executes **`initializePlugins()`** once during application startup, populating a **Zustand** store with the collections of registered plugins.

UI components throughout the application subscribe to this store using the registry-specific hooks. When a user interacts with the toolbar or opens a panel, the components query the appropriate registry to retrieve the React components defined in each plugin's `PluginDefinition`.

## Creating a Custom GeoLibre Plugin

To add new functionality, create a TypeScript file in `packages/plugins/src/plugins/` that exports a constant conforming to `PluginDefinition`:

```ts
// packages/plugins/src/plugins/example-plugin.ts
import { PluginDefinition } from '../types';

export const examplePlugin: PluginDefinition = {
  id: 'example-analysis',
  title: 'Example Analysis Tool',
  icon: '🔧',
  // Component rendered in the top toolbar
  ToolbarComponent: () => (
    <button onClick={() => console.log('Analysis running')}>
      Run Analysis
    </button>
  ),
  // Component rendered in the right panel when active
  RightPanelComponent: () => (
    <div>
      <h3>Analysis Settings</h3>
      <p>Configure your processing parameters here.</p>
    </div>
  ),
  // Function to create a custom map layer
  createLayer: (store) => {
    // Return layer configuration object
    return {
      id: 'analysis-layer',
      type: 'vector',
      source: store.getState().currentSource
    };
  }
};

```

After saving the file, the Plugin Manager automatically includes it in the next build. The toolbar will display the new button, the right panel will show the settings UI when activated, and the map will instantiate the specified layer according to the definition.

## Summary

- **Plugin Discovery**: The Plugin Manager in [`packages/plugins/src/plugin-manager.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/plugin-manager.ts) automatically discovers modules using wildcard imports from the `packages/plugins/src/plugins/` directory.
- **Type Safety**: All plugins must implement the `PluginDefinition` interface from [`packages/plugins/src/types.ts`](https://github.com/opengeos/GeoLibre/blob/main/packages/plugins/src/types.ts), ensuring consistent metadata and component structure.
- **Registry Pattern**: Specialized registries for toolbars, right panels, and floating windows handle UI integration, each exposing dedicated hooks for component access.
- **State Management**: The [`usePlugins.ts`](https://github.com/opengeos/GeoLibre/blob/main/usePlugins.ts) hook initializes the system and populates a Zustand store, making plugin data available throughout the React component tree.
- **Zero-Config Addition**: Simply adding a properly structured TypeScript file to the plugins directory automatically registers the functionality without manual imports.

## Frequently Asked Questions

### What is the minimum required code for a valid GeoLibre plugin?

A valid plugin requires only a file in `packages/plugins/src/plugins/` that exports an object with `id`, `title`, and `icon` properties conforming to the `PluginDefinition` interface. Optional properties like `ToolbarComponent` or `RightPanelComponent` enable specific UI integrations, but a plugin consisting solely of metadata is technically valid and will be registered, though it will not render visible UI elements.

### How does automatic plugin discovery work under the hood?

The Plugin Manager utilizes TypeScript's wildcard import capability (`import * as plugins from './plugins'`) combined with the build system's module resolution. When the application compiles, this import captures all modules in the plugins directory. The manager then iterates over the imported namespace, extracting each exported `PluginDefinition` and validating the required fields before adding them to the `pluginsById` map.

### Can a single plugin register components in multiple UI areas simultaneously?

Yes, a single `PluginDefinition` can include a `ToolbarComponent`, `RightPanelComponent`, and layer creation logic simultaneously. The Plugin Manager passes the complete definition to all three registries, and each registry extracts only the components relevant to its specific UI context. This allows cohesive features that span multiple interface areas while maintaining a single source of truth in one plugin file.

### Where should third-party or custom plugins be placed in a GeoLibre fork?

Custom plugins should reside in `packages/plugins/src/plugins/` following the naming convention [`your-feature-plugin.ts`](https://github.com/opengeos/GeoLibre/blob/main/your-feature-plugin.ts). Since the Plugin Manager uses automatic discovery rather than a static import list, placing files in this directory ensures registration without modifying core framework code. For distribution, plugins can be maintained as separate packages that export `PluginDefinition` objects, then imported into the plugins directory index.