Skip to content

geolens-io/geolens

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

211 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

GeoLens

English | Español | Français | Deutsch

Your team's spatial data — searchable, mappable, and shareable in one place.

GeoLens is an open-source, self-hosted catalog and map builder for GIS and data teams — a single home for spatial data that you run on infrastructure you control, with no telemetry and nothing leaving your network. Upload Shapefiles, GeoTIFFs, GeoPackages, or CSVs (or register data you already have); GeoLens stores everything in PostGIS, indexes it with pgvector + pg_trgm for semantic and fuzzy search, and serves OGC/STAC APIs that QGIS, ArcGIS, and MapLibre clients connect to natively. Compose, style, and share multi-layer maps right in the browser. Built on FastAPI and React. Deployed with one command.

CI License: Apache 2.0 Python: backend 3.13 / SDK 3.10+ PostgreSQL 17 + PostGIS 3.5 OGC Compliant

curl -fsSL https://getgeolens.com/install.sh | sh
# Open http://localhost:8080 — log in with the credentials you chose

GeoLens map builder with Manhattan building footprints extruded into a 3D skyline, color-graded by roof height, the layer style editor open beside the map
The map builder — Manhattan's building footprints extruded to roof height and color-graded by a data-driven style, built from open data with scripts/seed-showcase.py

Note

Early release — GeoLens is actively developed and maintained, and newly open-sourced. The core has run in production, but the self-hosted distribution is young and some features and APIs may still change — please open an issue if you hit a rough edge.

Documentation

Full user, admin, and API documentation lives at docs.getgeolens.com — the Reference table below links each guide.

Published Artifacts

GeoLens is published through the standard package registries:

pip install geolens          # Python SDK
pip install geolens-cli      # CLI; installs the `geolens` command
npm install @geolens/sdk     # TypeScript/JavaScript SDK

Prebuilt public API and frontend images are published to GitHub Container Registry:

docker pull ghcr.io/geolens-io/geolens-api:latest
docker pull ghcr.io/geolens-io/geolens-frontend:latest

The latest tag tracks the newest published stable release.

Why GeoLens?

Spatial data ends up scattered — shapefiles on shared drives, tables in database schemas, rasters in cloud buckets, metadata in spreadsheets. Finding the right dataset means asking Slack or grepping file servers. Sharing it means exporting, emailing, and hoping the CRS matches.

GeoLens replaces that workflow:

  • One catalog — upload Shapefiles, GeoPackages, GeoTIFFs, or CSVs and they become searchable, previewable, and exportable in minutes
  • Works with your tools — OGC API Features/Records, STAC API 1.0, direct tile URLs for QGIS, ArcGIS, and MapLibre
  • Semantic + spatial search — find datasets by meaning, not just keywords, powered by pgvector and pg_trgm full-text search
  • Built-in map builder — compose multi-layer maps, style them, and share via public link or embeddable iframe
  • AI-assisted (optional) — chat with your maps, auto-generate descriptions, search by natural language. Bring any OpenAI-compatible API key or skip it entirely

See It in Action

The examples below use a JWT bearer token. Mint one against the local stack (the login endpoint accepts an OAuth2 password form, so use -d with form fields, not JSON):

TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login/ \
  -d 'username=admin&password=admin' | jq -r '.access_token')

Search datasets by meaning, not just keywords:

# Semantic search ranks by meaning — "hydrology" surfaces subwatersheds, lakes,
# and river networks whose titles never mention the word
curl "http://localhost:8080/api/search/datasets/?q=hydrology&limit=3" \
  -H "Authorization: Bearer $TOKEN" | jq '.features[].properties.title'

Every dataset is also a standard OGC API Features endpoint:

# Grab a public collection id from the catalog. Search anonymously (no token) so
# the id is one anyone can read — matching the unauthenticated items request below.
CID=$(curl -s "http://localhost:8080/api/search/datasets/?q=countries&limit=1" \
  | jq -r '.features[0].id')

# GeoJSON features with a bbox filter — works in QGIS, ArcGIS, any OGC client
curl "http://localhost:8080/api/collections/$CID/items?bbox=-10,35,30,60&limit=5"

PostGIS and pgvector share one database, so you can rank datasets by meaning inside a spatial window in a single query — see the search guide for how semantic and spatial search work together.

Connect directly from QGIS: Layer > Add WFS / OGC API Features and point at http://localhost:8080/api/.

Features

The highlights above each have a full guide in the docs. What GeoLens reads, writes, and exposes:

Data Ingestion and Export

  • Vector: Shapefile, GeoPackage, GeoJSON, CSV, XLSX
  • Raster: GeoTIFF and Cloud-Optimized GeoTIFF (COG) with automatic conversion
  • Mosaics: VRT-based raster mosaics from multiple source files
  • Export: GeoJSON, Shapefile, GeoPackage, CSV, with CRS reprojection
  • Provenance tracking and metadata editing

Standards and Interop

  • OGC API - Features and OGC API - Records; STAC API 1.0 catalog endpoint
  • Direct tile URLs and per-user API keys for QGIS, ArcGIS, MapLibre, and any OGC client
  • JWT + OAuth 2.0/OIDC, RBAC with per-dataset permissions
Security
  • JWT authentication with refresh tokens
  • API key management per user
  • OAuth 2.0 / OIDC support (Google, Microsoft, generic providers)
  • Role-based access control (RBAC) with per-dataset permissions
  • Audit logging for all administrative actions
  • Internationalization: English, Spanish, French, German

Screenshots

GeoLens catalog search for 'hydrology' returning ranked hydrology datasets — subwatersheds, lakes, and river networks — with type and spatial filters
Find — search by meaning: a query for "hydrology" ranks subwatersheds, lakes, and river networks, with type, spatial, and temporal filters

GeoLens dataset detail for Natural Earth river centerlines: a global map preview above a typed attribute table with per-column filters
Inspect — every dataset gets a map preview, schema stats, and a typed, filterable attribute table (here: 1,473 river centerlines, 38 columns)

GeoLens map builder rendering the Matterhorn as a 3D terrain mesh from swissALTI3D lidar, with labeled peaks, climbing routes, the drag-orderable layer stack, and a legend
Build — compose multi-layer maps in the browser with a drag-orderable layer stack and per-layer editors (here: the Matterhorn as a 3D terrain mesh from swissALTI3D lidar)

GeoLens Ask AI panel adding county-name labels to a New York median-income choropleth from the natural-language request 'Add area labels'
Ask AI — edit maps in natural language: "add area labels" puts county names on a New York income choropleth (optional — bring your own OpenAI-compatible key)

Quick Start

Prerequisites: Docker Engine 24+ and Docker Compose v2. The bundled stack ships PostgreSQL 17. If you point GeoLens at an externally managed database, it must be PostgreSQL 13+ (for gen_random_uuid()) with pgvector 0.5+ (for HNSW semantic-search indexes), plus PostGIS, pg_trgm, and unaccent.

The one-line install pulls the prebuilt, version-pinned images and starts the stack:

curl -fsSL https://getgeolens.com/install.sh | sh

Prefer to read the script or build from source first? Clone the repo and run the same installer — it builds the images locally instead of pulling them:

git clone https://github.com/geolens-io/geolens.git
cd geolens
bash scripts/install.sh

Either way, scripts/install.sh copies .env.example to .env, generates a JWT signing secret, prompts for admin credentials (defaults to admin / admin), and runs docker compose up -d. For unattended installs, set GEOLENS_ADMIN_USERNAME and GEOLENS_ADMIN_PASSWORD in the environment before running and the prompts are skipped. Re-running the script is idempotent — existing values in .env are preserved.

Wait about 60 seconds for services to start, then open http://localhost:8080. Log in with the admin credentials you set.

Verify all services are healthy:

docker compose ps

First-run notes: the one-line install pulls prebuilt images and is up in about a minute (only the small PostGIS + pgvector database layer builds locally). Cloning and running bash scripts/install.sh instead builds every image from source — 5-10 minutes on the first run (GDAL + Postgres extensions + the frontend bundle); subsequent starts settle in ~60 seconds either way. If ports 5434/8001/8080 are already taken, change DB_PORT, API_PORT, or FRONTEND_PORT in .env. For port conflicts, stuck startups, out-of-memory, and migration warnings, see the Troubleshooting guide.

For production deployment, see the Install Guide. A community-maintained Kubernetes Helm chart lives in the separate geolens-deployments repo. For upgrading, see the Upgrade Guide.

Add Your First Dataset

The repo ships a small city-parks.geojson. Upload and publish it in one command with the GeoLens CLI:

pip install geolens-cli                              # installs the `geolens` command
geolens login http://localhost:8080/api              # admin / admin
geolens publish examples/manifests/first-catalog/city-parks.geojson --name "City Parks"

geolens publish runs the upload → preview → commit ingest flow and prints the new dataset's URL — clone to first dataset in one command.

For repeatable, multi-dataset catalogs, describe your sources in a manifest (geolens.yaml) and apply it with geolens apply. Manifest sources are referenced by HTTP(S) URL, S3 URI, or a path already staged on the server; the examples in examples/manifests/ are templates to adapt. Scaffold a fresh one with geolens init and edit it for your sources:

geolens init                       # writes geolens.yaml in the current directory
geolens validate geolens.yaml      # local schema check, no API call
geolens apply geolens.yaml         # validates + applies via /ingest/manifest/apply

See the CLI guide for the full manifest schema, source kinds, and CI integration patterns.

Seed Data

scripts/seed-showcase.py builds three showcase maps from public open data — a Manhattan 3D skyline (the hero above), a New York income choropleth, and an optional Matterhorn 3D-terrain hero:

pip install httpx
python scripts/seed-showcase.py --username admin --password admin [--with-terrain] [--only manhattan|income|matterhorn]

Requires internet access to the upstream open-data sources.

Architecture

GeoLens is a small set of services around a single PostgreSQL/PostGIS database: the API serves the catalog, search, and OGC/STAC endpoints; a worker handles ingestion; and Titiler serves raster tiles from object storage.

flowchart TB
    B["Browser — React + MapLibre app"]
    OGC["QGIS · ArcGIS · OGC/STAC clients"]

    NG["Nginx — reverse proxy<br/>serves the React build, routes /api and tiles"]

    subgraph Application
      API["FastAPI<br/>catalog · semantic search · OGC/STAC · vector tiles"]
      W["Worker<br/>GDAL/ogr2ogr ingestion"]
      TT["Titiler<br/>COG raster tiles"]
    end

    subgraph store [Data and storage]
      PG[("PostgreSQL 17<br/>PostGIS · pgvector · pg_trgm<br/>+ Procrastinate queue")]
      OBJ[("Object storage<br/>local files or S3/MinIO")]
      CACHE[("Valkey cache")]
    end

    B --> NG
    OGC --> NG
    NG --> API
    NG --> TT
    API <--> PG
    API --> OBJ
    API -. tile/query cache .-> CACHE
    PG == job ==> W
    W --> PG
    W --> OBJ
    TT --> OBJ
Loading
Component Technology
Frontend React 19, Vite, MapLibre GL v5, TanStack Query, Tailwind CSS
Backend API FastAPI (Python), GDAL/ogr2ogr, Procrastinate (task queue)
Raster Tiles Titiler (COG tile server)
Object Storage MinIO (S3-compatible, local dev) or any S3 provider
Cache Valkey (tile and query cache)
Database PostgreSQL 17 + PostGIS 3.5 + pgvector + pg_trgm (minimum: PostgreSQL 13, pgvector 0.5)
Reverse Proxy Nginx (production) / Vite dev proxy (development)

Configuration

All configuration is managed through environment variables in .env. See the Configuration Reference for the full list of options with defaults and descriptions.

Connection Pool Budget

GeoLens ships tuned for a single PostgreSQL instance: the API, worker, and admin pools fit within 30 of 30 max_connections out of the box (PERF-05 — Postgres max_connections lowered from 50 → 30), sized by DB_POOL_SIZE (pool_size) and DB_MAX_OVERFLOW (max_overflow, default 3). See Connection Pool Tuning for the per-process budget and how to raise the ceiling.

Backup S3 Compatibility

Automated off-site backups to S3-compatible storage (MinIO, Cloudflare R2, AWS S3) ship via the backup Compose profile. New AWS buckets require Signature V4 — see Backups & Restore for the Sig-V2 compatibility note and the aws-cli workaround.

Reference

Guide Description
Install Guide Step-by-step deployment with Docker Compose
Upgrade Guide Upgrading between versions with rollback procedures
Configuration Reference All environment variables and their defaults
Admin Guide User management, datasets, system health
Cloud Deployment AWS, GCP, and DigitalOcean deployment guides
CLI & Manifests Publish files and manage catalogs with the geolens CLI
API Reference Auto-generated reference at docs.getgeolens.com; interactive Swagger UI at /api/docs when running
Manifest examples Template geolens.yaml manifests to adapt — public-cog (remote COG), url-source, s3-source, publication-states

Community

License

GeoLens is licensed under the Apache License 2.0. The GeoLens name, logo, and brand assets are not covered by this license.