Build an OGC API Features service: production guide for interoperable geospatial data
OGC API Features is a modern web interface for publishing and querying vector geospatial data at the feature level. This production guide explains the standard’s resource model, how to select and prepare a backend, how to publish collections with pygeoapi, how to test discovery and feature queries, and which operational details matter for coordinate reference systems, pagination, filtering, security, freshness, and scale.
An OGC API Features service exposes geographic objects—such as roads, buildings, hydrants, parcels, waterways, permits, or service locations—through predictable web resources. Unlike a map image service, it gives clients access to individual features and their properties. Unlike a database connection, it provides a documented HTTP interface that can be consumed by GIS software, scripts, web applications, and other services. The standard is intentionally modular: Part 1, Core, defines mandatory read access and discovery resources; additional parts extend coordinate reference systems, filtering, transactions, and schemas. This guide uses pygeoapi as a concrete implementation example, while keeping the architecture applicable to other compliant servers.
How EDK fits
For: GIS developers, geospatial data engineers, platform teams, public-data publishers, and software engineers who need to expose vector data through a standards-based HTTP API.
OGC API Features is directly relevant to a world-model approach because it turns physical-world observations into discoverable, addressable, machine-readable features. A road, building, stream, fire hydrant, construction permit, or public asset can be represented as a feature collection, queried by bounding box, retrieved by identifier, and combined with other geographic information. That is the access layer needed before broader geographic computation can happen. An OGC API Features service does not itself provide a complete world model, universal search system, routing engine, or cross-source analytical layer; it is an interoperable way to publish and retrieve feature data. In an E2-oriented workflow, such a service can act as an external source for finding real-world features, inspecting their attributes and geometry, and supplying inputs for operations such as proximity checks, regional aggregation, ranking, change analysis, or comparisons across places.
- •Publish a collection of physical features—such as residential roads, streams, parks, streetlights, hydrants, buildings, permits, or service requests—so they can be discovered and retrieved consistently alongside other geographic sources.
- •Use feature-level access as an input to geographic computation: retrieve features within a bounding box, inspect their properties, compare collections across neighborhoods, or calculate relationships such as proximity and containment in a separate spatial analysis layer.
- •Preserve a clean boundary between data publication and world-model computation: the OGC API service remains the authoritative interface for a particular dataset, while a broader geographic system can index, normalize, relate, and compute across many such services.
The EDK outcome
Before you start
A vector dataset with known geometry, identifiers, attributes, coordinate reference system, source license, and update policy.
Basic familiarity with HTTP, JSON, GeoJSON, command-line requests, and geographic coordinate order.
A Python 3 environment or Docker if following the pygeoapi example.
A spatial database such as PostgreSQL with PostGIS for a database-backed production deployment, or a supported file-based provider for smaller datasets.
A plan for HTTPS, authentication and authorization, rate limiting, monitoring, backups, attribution, and data refreshes.
Learning objectives
Explain the resource model and scope of OGC API Features Part 1: Core.
Select a suitable backend and map it to a published feature collection.
Test discovery, feature retrieval, bounding-box queries, pagination, and representations.
Identify provider-specific limitations instead of assuming every advertised operation is available.
Operate the service with stable identifiers, explicit CRS behavior, security controls, observability, and compliance testing.
Verification
The landing page identifies the API and links to its collections, conformance declaration, and API definition where applicable.
The `/conformance` response lists only conformance classes actually implemented and tested.
The collection description exposes correct identifiers, extent, geometry expectations, links, attribution, and update information.
Feature responses use the documented media type and contain valid geometry, stable IDs, and reviewed properties.
Bounding-box queries return features in the expected geographic area and coordinate order.
Pagination does not duplicate or skip features under the documented consistency model.
Unknown collections, feature IDs, malformed parameters, and unsupported operations return predictable HTTP errors.
Database queries remain within acceptable latency and response-size limits at realistic production volumes.
Security controls prevent unauthorized administration or editing, especially if transactions are enabled.
Troubleshooting
A blank or incomplete collections response often indicates an invalid provider configuration, missing source file, unavailable database, or collection-level metadata error. Inspect server logs and request the collection directly.
If geometries appear in the wrong place, check longitude-latitude ordering, the storage CRS, the advertised CRS, and any transformation performed by the provider. Do not fix a display problem by swapping coordinates blindly.
If a bounding-box query is slow, inspect the database query plan, confirm a spatial index exists, reduce the response limit, and verify that the API is not retrieving every property or geometry unnecessarily.
If a property filter returns no results, confirm the published property name, data type, case behavior, provider support, and whether the implementation supports that query parameter for the selected backend.
If pagination is inconsistent during updates, document the service’s consistency behavior and consider snapshotting, versioned extracts, stable ordering, or a bulk-download workflow.
If an alternate CRS request fails, inspect the `/conformance` declaration and provider support matrix. Part 1 alone does not guarantee CRS transformation or CRS-by-reference support.
If transactions are exposed accidentally, disable them until authentication, authorization, audit logging, validation, and rollback procedures are in place.
If clients reject the response, check the media type, JSON structure, link relations, CORS policy, HTTPS certificate, and whether the client expects a particular OGC API version or extension.
Next steps
Add automated contract tests that run against every deployment and dataset refresh.
Publish collection-level metadata, licensing, attribution, provenance, and freshness information.
Add database indexes and query limits based on observed access patterns rather than assumptions.
Evaluate OGC API Features Part 2, Part 3, Part 4, or Part 5 only when a concrete client requirement justifies the added implementation and testing surface.
Connect the service to a broader geographic workflow that can relate features across collections, compute proximity or containment, aggregate by region, and compare changes over time.
Document stable collection IDs and a deprecation policy before external clients begin depending on the API.
What OGC API Features provides—and what it does not
OGC API Features is a multi-part OGC standard for sharing feature data through web APIs. Part 1: Core defines the mandatory read-access capabilities. Its resource model includes a landing page at the API root, a conformance declaration at `/conformance`, a collections resource at `/collections`, individual collection descriptions, a collection’s `/items` resource, and individual feature resources such as `/collections/{collectionId}/items/{featureId}`. The published standard describes these resources and their relationships in detail. (ogcapi.ogc.org)
The standard is not a database schema, hosting platform, authentication system, map renderer, or universal query language. Your service still needs a data store, deployment environment, access-control policy, monitoring, backup strategy, and a clear data-maintenance process. The OGC Common specification provides shared conventions for discovery, links, conformance, and API descriptions, but it does not define a complete security model. (docs.ogc.org)
- •Use OGC API Features when clients need individual geographic features and their attributes, not only rendered map images.
- •Use a separate map, tiles, coverage, records, routing, or processing API when those are the actual resource types or operations required.
- •Advertise only the conformance classes and query capabilities that the deployed implementation really supports.
Prerequisites and architecture decisions
Before writing configuration, define the dataset you are publishing. Record its feature type, stable identifier, geometry type, source coordinate reference system, update cadence, licensing, attribution requirements, and expected query patterns. A collection of streetlights has different indexing and response-size concerns from a collection of regional polygons or historical service requests.
You also need a serving strategy. A file-backed source can be appropriate for a small, relatively static GeoJSON or GeoPackage dataset. A spatial database is usually a better fit for large collections, frequent updates, spatial indexes, property filtering, and multiple concurrent clients. The implementation example below uses pygeoapi because its official documentation provides concrete providers for GeoJSON, PostgreSQL/PostGIS, GeoPackage, Elasticsearch, and other backends. It is an example implementation, not a requirement of the OGC standard. (docs.pygeoapi.io)
- •Python 3 if following the pygeoapi example.
- •A representative vector dataset with known geometry and property semantics.
- •A domain name or externally reachable test endpoint.
- •A database with PostGIS enabled if using the PostgreSQL provider.
- •A plan for attribution, licensing, access control, backups, refreshes, and deprecation.
Step 1: install an implementation and create a baseline service
The following commands use pygeoapi’s documented installation workflow. Pin a tested release for production rather than relying on a moving `latest` tag. The official documentation describes both Python installation and container images. (docs.pygeoapi.io)
- •Create an isolated environment:
- •Generate or copy a configuration file and an OpenAPI output path.
- •Start locally and verify the root endpoint before adding your own data.
Step 2: configure a feature collection
A collection configuration should make the dataset understandable without requiring clients to inspect the source database. Give it a stable identifier, title, description, extent, item type, attribution, and links where the implementation supports them. The provider definition then maps the collection to a source table, file, or external service.
For a PostgreSQL/PostGIS-backed collection, pygeoapi’s documented configuration identifies the database connection, table, identifier field, and geometry field. The provider supports several useful operations, including bounding-box queries, property filtering, sorting, temporal queries, counts, and transactions, but the exact support depends on the provider and configuration. Treat the provider capability matrix as an implementation constraint rather than assuming every OGC API Features operation is available everywhere. (docs.pygeoapi.io)
- •Use a stable, non-changing identifier for each feature. Avoid using a row number that can change after reloads.
- •Create a spatial index on the geometry column and indexes on properties that are commonly filtered or sorted.
- •Keep the published property names deliberate. Do not expose internal fields, secrets, or unreviewed personal information.
- •Make geometry semantics explicit: point, line, polygon, or a permitted collection type, along with the coordinate reference system and axis-order expectations.
Step 3: expose and inspect the standard discovery resources
Once the server is running, inspect the API in the same order a generic client would. Start with the landing page, then the conformance declaration, then the collections list, then one collection, and finally its items. This sequence catches configuration errors earlier than jumping directly to a complex query.
A minimal smoke-test sequence looks like this:
- •Landing page: `GET /`
- •Conformance: `GET /conformance`
- •Collections: `GET /collections`
- •Collection metadata: `GET /collections/roads`
- •Feature list: `GET /collections/roads/items`
- •Single feature: `GET /collections/roads/items/{id}`
- •OpenAPI description: follow the API’s advertised API-definition link or configured OpenAPI document.
Step 4: test geographic queries, pagination, and representations
Test the query behavior that your clients actually need. A bounding-box query is often the first geographic operation because it allows a map or data application to request only features in the current view. Pagination is essential for large collections; never assume that a collection can be downloaded safely in one response.
With pygeoapi, the documented examples include `bbox`, `limit`, `offset`, feature identifiers, alternate output formats, property queries, temporal queries, sorting, and CRS parameters where the provider supports them. The documentation also notes that the default CRS is CRS84 with longitude-latitude ordering when no other CRS is supplied in the relevant configuration. Validate this behavior with real coordinates rather than relying on a client’s display. (docs.pygeoapi.io)
- •`curl -H 'Accept: application/geo+json' 'http://localhost:5000/collections/roads/items?bbox=-73.99,40.73,-73.98,40.74&limit=25'`
- •`curl -H 'Accept: application/geo+json' 'http://localhost:5000/collections/roads/items?offset=25&limit=25'`
- •`curl 'http://localhost:5000/collections/roads/items/{feature-id}'`
- •`curl 'http://localhost:5000/collections/roads/items?f=csv'` when the configured provider and formatter support CSV.
Step 5: validate, secure, and operate the service
Validation should cover both protocol behavior and geographic correctness. Confirm that every advertised link resolves, collection identifiers are stable, feature identifiers are unique within a collection, geometries are valid, coordinates appear in the expected order, and response content types match the representation. Test empty result sets, unknown collections, unknown feature identifiers, invalid bounding boxes, oversized limits, and malformed dates.
Run the OGC API Features compliance tests where applicable. OGC publishes compliance information and an executable test suite for Part 1: Core; certification is separate from simply using a familiar URL pattern. A service should not be described as certified unless the relevant product and version have actually passed the applicable OGC process. (portal.ogc.org)
- •Publish a version or freshness indicator for the underlying dataset.
- •Use database connection pooling carefully and set connection timeouts.
- •Cache safe, repeated metadata requests, but avoid caching responses whose data freshness or authorization varies.
- •Load-test bounding-box queries at realistic map extents and zoom levels.
- •Document deprecation dates and migration paths before changing collection IDs or property names.
Workflow
Install pygeoapi in an isolated environment
The following is a concrete implementation path. For production, replace unpinned development commands with a tested release and repeatable build process.
python3 -m venv pygeoapi
. pygeoapi/bin/activate
python -m pip install --upgrade pip
python -m pip install pygeoapi
# After creating or copying a configuration file:
export PYGEOAPI_CONFIG=example-config.yml
export PYGEOAPI_OPENAPI=example-openapi.yml
pygeoapi openapi generate "$PYGEOAPI_CONFIG" --output-file "$PYGEOAPI_OPENAPI"
pygeoapi serveRun the documented container image for a local baseline
Use the official pygeoapi image to verify that the runtime and basic HTTP service work before adding your own backend.
docker pull ghcr.io/geopython/pygeoapi:latest
docker run --rm -p 5000:80 ghcr.io/geopython/pygeoapi
curl -i http://localhost:5000/
curl -i http://localhost:5000/conformance
curl -i http://localhost:5000/collectionsMap a PostGIS table to a feature collection
Use a stable identifier column and a geometry column with a known CRS. The exact surrounding YAML depends on the pygeoapi release and configuration template, so validate the complete file against the version you deploy.
providers:
- type: feature
name: PostgreSQL
data:
host: 127.0.0.1
port: 5432
dbname: geodata
user: api_reader
password: ${POSTGRES_PASSWORD}
search_path: [public]
id_field: road_id
table: roads
geom_field: geom
count: trueExercise the feature endpoints
Replace `roads` and the bounding box with identifiers and coordinates from your own collection. Confirm the response content type, links, geometry, properties, and pagination metadata.
curl -H 'Accept: application/geo+json' \
'http://localhost:5000/collections/roads/items?bbox=-73.99,40.73,-73.98,40.74&limit=25'
curl -H 'Accept: application/geo+json' \
'http://localhost:5000/collections/roads/items/12345'
curl 'http://localhost:5000/collections/roads/items?offset=25&limit=25'Run protocol and geographic validation
Automate tests for discovery, invalid requests, empty results, coordinate order, stable identifiers, geometry validity, response size, and representative query latency. Then run the applicable OGC compliance tests for the conformance classes you claim.
# Example checks; adapt to your test framework
curl --fail http://localhost:5000/
curl --fail http://localhost:5000/conformance
curl --fail http://localhost:5000/collections
curl --fail 'http://localhost:5000/collections/roads/items?limit=1'
# Also test:
# - unknown collection
# - unknown feature id
# - invalid bbox
# - limit above the service maximum
# - empty bbox result
# - malformed datetime
# - missing or reversed coordinate assumptionsQuestions teams ask
Is OGC API Features the same thing as WFS?
No. They address related feature-access needs, but OGC API Features follows a modern resource-oriented web API approach with landing pages, links, conformance declarations, collections, OpenAPI descriptions, and commonly JSON-based representations. WFS is an earlier OGC web service family with different protocol and encoding conventions. An OGC API Features service should be documented and tested against its own conformance requirements rather than treated as a renamed WFS endpoint.
Do I need PostGIS to build an OGC API Features service?
No. PostGIS is one backend option. A compliant implementation can publish from other supported stores or files, depending on the server. PostGIS is attractive when you need spatial indexes, database-managed updates, concurrent access, and more advanced geographic queries. A small static dataset may be better served from GeoJSON, GeoPackage, or another supported source.
Does Part 1 automatically support filtering and editing?
No. Part 1: Core is focused on mandatory read access and discovery. Filtering, coordinate reference systems by reference, transactions, and schemas are covered by additional parts or implementation-specific capabilities. Check `/conformance`, the API definition, and actual request tests before depending on a capability.
Should an OGC API Features service return every feature in a collection?
Usually not. Use pagination and bounded queries. For interactive maps, request the current view or another deliberately chosen geographic extent. For analytical extraction, provide documented limits, stable pagination behavior, and an export or bulk-delivery workflow when appropriate.
Where does OGC API Features fit in a larger geographic system?
It is a feature-publication and access interface. It can supply roads, buildings, infrastructure, environmental features, permits, public assets, or other geographic objects to systems that index, relate, measure, rank, compare, or aggregate information about physical places. It does not by itself provide a unified world model or perform every cross-dataset computation.
Keep exploring
consume wfs in python
Useful when integrating an existing WFS and comparing older feature-service workflows with OGC API Features.
build a web map with maplibre production guide
Covers the browser-side map application that can consume feature or tile services while keeping rendering separate from geographic data access.
analyze spatial data with geopandas production guide
Shows how retrieved vector features can be validated, transformed, joined, measured, and analyzed in a production data workflow.
Sources
OGC API - Features overview and standards
Official OGC overview of the multipart standard, Part 1 scope, additional parts, API definitions, implementations, and compliance testing.
Open sourceOGC API - Features - Part 1: Core
The normative Part 1 document defining the core resources and requirements for feature access.
Open sourceOGC API - Common - Part 1: Core
Official specification for shared OGC API conventions including discovery, conformance, links, and API behavior.
Open sourcepygeoapi installation documentation
Official implementation documentation covering Python installation, Docker images, configuration, and startup.
Open sourcepygeoapi publishing vector data to OGC API - Features
Official provider capability matrix, PostgreSQL/PostGIS configuration examples, query examples, CRS behavior, and format support.
Open sourceOGC API Features compliance testing
Official OGC information about the Part 1 compliance test suite and the purpose of feature-level access.
Open source