.geolibre.json Project File Structure: A Complete Guide to GeoLibre's Core Format
The .geolibre.json file is a JSON-based project descriptor that stores map layers, plugin states, view settings, and global preferences in a round-trippable format compatible with the MapLibre style specification.
GeoLibre uses the .geolibre.json extension to persist complete map projects. This file format serves as the single source of truth for reconstructing a map, from layer styling and visibility to camera position and plugin configurations. Understanding this structure is essential for developers building automation tools, custom plugins, or server-side generators that interact with the opengeos/GeoLibre codebase.
Top-Level Keys in a .geolibre.json File
A valid .geolibre.json file contains several required top-level keys that define the project state. According to docs/project-format.md and the TypeScript definitions in packages/core/src/types.ts, the schema includes:
name– Human-readable project title displayed in the UI.layers– Ordered array of layer definitions describing vector, raster, tile, GeoJSON, or plugin-based layers.plugins– Array of plugin state objects storing configuration for both built-in and third-party extensions.view– Camera viewport settings including center coordinates, zoom, bearing, and pitch.settings– Global UI and processing preferences such as measurement units, language, and map style.metadata(optional) – Free-form object for arbitrary project-specific data like author information or provenance.version(optional) – Schema version identifier to aid forward compatibility when absent.
Deep Dive into the Layers Array
The layers array is the heart of the .geolibre.json structure. Each element follows the Layer interface defined in packages/core/src/types.ts and supports properties compatible with the MapLibre GL style specification.
Layer Types and Source Configuration
Every layer object requires an id, type, and source field:
{
"id": "countries-layer",
"type": "geojson",
"source": {
"url": "https://example.com/countries.geojson"
},
"visible": true,
"opacity": 1.0
}
Supported type values include "vector", "raster", "tile", "geojson", and "plugin". The source object varies by type, accepting URLs, file paths, or DuckDB queries depending on the data provider.
Styling with layout and paint Properties
Layer styling uses layout and paint objects that mirror the MapLibre style spec:
{
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "#88c0d0",
"fill-opacity": 0.8
}
}
These properties control rendering behavior, allowing the same styling logic used in pure MapLibre applications to apply directly to GeoLibre projects.
Plugin State Management
The plugins array stores serialized state for extensions, enabling third-party tools to survive export and import cycles. As defined in packages/plugins/src/types.ts, each entry contains:
id– Plugin identifier (e.g.,"draw","measure","my-plugin").enabled– Boolean flag indicating whether the plugin is active.config– Arbitrary JSON object defined by the plugin's internal schema.
{
"id": "my-plugin",
"enabled": true,
"config": {
"threshold": 0.75,
"colorScheme": "viridis"
}
}
The core application stores these objects verbatim in useAppStore, allowing plugins to declare their own schema extensions without core modifications.
View and Settings Configuration
The view object captures camera state using the ViewState interface:
{
"view": {
"center": [0, 0],
"zoom": 2,
"bearing": 0,
"pitch": 0
}
}
The settings object contains global preferences defined in the Settings interface:
units–"metric"or"imperial".language– I18n locale code (e.g.,"en").mapStyle– MapLibre style URL or built-in style name.maxZoom/minZoom– Zoom constraints.- Feature toggles – Such as
enableMCPorshowLegend.
Working with .geolibre.json Files Programmatically
GeoLibre provides several APIs for programmatic project manipulation across different environments.
Loading Projects via Embed URLs
The @geolibre/embed package exposes parseEmbedRequest for handling external project URLs:
import { useEffect } from 'react';
import { parseEmbedRequest } from '@geolibre/embed';
useEffect(() => {
const message = {
type: 'loadProject',
url: 'https://example.com/my-map.geolibre.json'
};
const embedMessage = parseEmbedRequest(message);
// embedMessage.command contains { type: 'loadProject', url: '...' }
// The core store validates the JSON against the schema and populates the UI
}, []);
This pattern allows web applications to initialize GeoLibre with a specific .geolibre.json file via query parameters or postMessage APIs.
Generating Projects in Python
Server-side applications can construct valid project files using standard JSON libraries:
import json
project = {
"name": "Server-Generated Demo",
"layers": [
{
"id": "urban-areas",
"type": "vector",
"source": {"url": "mbtiles://data/cities.mbtiles"},
"layout": {"visibility": "visible"},
"paint": {"fill-color": "#5e81ac"},
"visible": True,
"opacity": 0.9
}
],
"view": {"center": [10.0, 59.0], "zoom": 10, "bearing": 0, "pitch": 0},
"settings": {"language": "en", "units": "metric", "mapStyle": "streets"}
}
with open("output.geolibre.json", "w") as f:
json.dump(project, f, indent=2)
Persisting Plugin Configuration
Custom plugins interact with the global store to persist state:
useAppStore.getState().addPlugin({
id: "custom-analytics",
enabled: true,
config: {
autoRefresh: 300,
dataSource: "duckdb://analytics.db"
}
});
This state is automatically included in the next project save operation.
File Naming and Validation
When saving projects through the desktop interface, the helper function ensureProjectFileName (tested in tests/file-names.test.ts) automatically appends the .geolibre.json suffix if the user omits it. The loading logic in apps/geolibre-desktop/src/hooks/useProjects.ts validates incoming JSON against the TypeScript interfaces, ensuring that malformed files trigger appropriate error handling before corrupting the application state.
Summary
- The
.geolibre.jsonformat stores layers, plugins, view, and settings in a single JSON object. - Layer definitions use MapLibre-compatible
layoutandpaintproperties for styling. - The format is extension-friendly, allowing plugins to store arbitrary configuration objects under the
pluginsarray. - Projects are round-trippable, meaning saved files can be reloaded without loss of UI state, camera position, or layer visibility.
- Source definitions reside in
packages/core/src/types.tsandpackages/plugins/src/types.ts, while file handling logic lives inapps/geolibre-desktop/src/hooks/useProjects.ts.
Frequently Asked Questions
What is the difference between .geolibre.json and MapLibre Style JSON?
While both use similar styling objects, .geolibre.json is a project wrapper that includes UI state (layer visibility, opacity, plugin configurations, and camera view) whereas MapLibre Style JSON focuses strictly on rendering rules and data sources. GeoLibre projects can reference external MapLibre styles via the settings.mapStyle property while maintaining additional project-specific metadata.
How do I add a custom layer to a .geolibre.json file?
Add a new object to the layers array with a unique id, valid type (such as "geojson" or "vector"), and appropriate source configuration. Include visible and opacity flags for UI control, plus layout and paint objects following the MapLibre specification. The application will render the layer immediately upon loading the project.
Can I manually edit a .geolibre.json file in a text editor?
Yes, the format is plain JSON and human-readable. However, you must preserve the schema structure defined in packages/core/src/types.ts to ensure the file loads correctly. Invalid JSON or missing required fields (like id for layers) will cause validation errors when the application attempts to import the project.
How does GeoLibre handle backward compatibility for older project files?
The optional version field at the top level of the JSON indicates the schema version used when creating the file. When this field is absent, the application assumes the current schema version. The loading logic in useProjects.ts includes migration handlers that upgrade legacy structures to the current format, ensuring older .geolibre.json files remain functional across application updates.
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 →