Create a STAC catalog: production guide for organizing spatiotemporal assets
A STAC catalog is a linked, machine-readable structure for discovering spatiotemporal assets. This production guide explains how to design the catalog hierarchy, create STAC Collections and Items with PySTAC, attach assets and metadata, normalize links, publish the result as static files, validate the catalog, and prepare it for later API-based search. It emphasizes the boundary between describing geographic assets and performing analysis on those assets.
The SpatioTemporal Asset Catalog specification, commonly called STAC, provides a shared structure for describing and discovering files or services that represent information about the Earth at particular places and times. A STAC implementation can describe satellite imagery, aerial photography, point clouds, data cubes, video, elevation products, or other geospatial assets without forcing every provider to expose the underlying data in the same storage format. (stacspec.org) Creating a catalog is therefore not just a matter of writing one JSON file. You must decide what an Item represents, when to use a Collection instead of a plain Catalog, how assets are linked, which metadata is searchable, how files are laid out, how links behave after publication, and how you will validate the complete graph. This guide uses a static catalog created with PySTAC because it makes those decisions visible and produces files that can later be hosted on ordinary HTTP or object storage.
How EDK fits
For: GIS developers, remote-sensing engineers, data publishers, geospatial platform teams, and analysts who need to publish a reliable collection of geographic assets for discovery or downstream computation.
STAC is closely related to the problem of finding and understanding the physical world because it gives geographic assets a common descriptive layer: each Item can carry a spatial geometry, time information, links, searchable properties, and one or more data assets. That makes imagery, elevation, point-cloud, environmental, and other Earth-observation resources easier for software to discover and relate to a place and time. STAC does not itself become a world model, raster-processing engine, routing system, geocoder, or spatial database. It is a cataloging and discovery standard. Its value in a broader world-model workflow is that it supplies structured provenance and asset references that can be connected to other geographic features, boundaries, roads, buildings, waterways, infrastructure, or observations before computation begins. The STAC specifications explicitly separate the simple linking role of Catalogs from the richer metadata of Collections and the asset-bearing, GeoJSON-based Item object. (github.com)
- •Use STAC as the discovery layer for imagery or environmental assets that will later be searched by area, date, collection, cloud cover, sensor, or other metadata before being compared with physical features such as roads, buildings, vegetation, waterways, or public infrastructure.
- •Use a STAC Collection and its Items as provenance-aware inputs to geographic computation: select the assets intersecting a region, retrieve the linked files, and then measure, rank, compare, aggregate, or detect change across the represented geography. STAC describes and links the inputs; the downstream spatial or raster-processing system performs the computation.
- •Use nested Catalogs or Collections to organize large geographic archives by date, geography, sensor, processing level, or other operational partitions, while preserving links that allow clients to crawl the published structure.
The EDK outcome
Before you start
Python 3 and a virtual environment.
A sample geographic asset or a durable URL to one.
A defined Item granularity and identifier policy.
A valid geometry and UTC acquisition time for each Item.
Collection-level information such as license, provider, spatial extent, and temporal extent.
A publication root that will remain stable after deployment.
Learning objectives
Explain the difference between a STAC Catalog, Collection, Item, and Asset.
Create a linked static catalog with PySTAC.
Attach geographic assets and searchable spatiotemporal metadata.
Normalize HREFs into a predictable publication layout.
Validate STAC objects, links, assets, and dataset-specific geographic constraints.
Recognize when a static catalog should be supplemented by an index or STAC API.
Verification
The root document has `type`, `stac_version`, `id`, `description`, and `links`.
Every Collection has the required license and spatial and temporal extent information.
Every Item has a stable ID, valid geometry, bounding box, UTC datetime or an explicitly supported interval representation, and links or assets appropriate to the dataset.
Items in a Collection point back to that Collection as required by the Collection specification.
Relative links resolve from the generated file location, and absolute links resolve from the deployed publication root.
Asset media types and roles describe the actual files rather than the intended files.
The catalog passes schema validation and best-practice checks.
A clean environment can retrieve and parse the published root document without relying on local build paths.
Troubleshooting
Broken relative links: normalize HREFs against the directory that will be published, not against a temporary development directory. Inspect the generated `self`, `root`, `parent`, `child`, `collection`, and `asset` links.
Item rejected because of missing datetime: provide an aware UTC `datetime`, or use the supported start and end datetime fields when the asset represents a time interval. Do not insert JSON `null` unless the relevant STAC specification explicitly permits it. (github.com)
Geometry and bounding box disagree: calculate the bounding box from the same geometry used in the Item, and verify longitude-latitude coordinate order.
Collection validation fails: check license, extent arrays, provider metadata, and the relationship between the Collection and its Items. A Collection is not just a renamed Catalog; it adds dataset-level requirements. (github.com)
Assets return 403 or 404: validate credentials, object-storage policies, URL encoding, case-sensitive filenames, and whether the published asset path differs from the local path.
Clients cannot discover the data: check that Catalogs and Collections contain navigable links, that Items link back to their Collection, and that the chosen metadata fields are actually present and consistently named.
Validation passes but users receive bad results: add domain-specific tests for stale metadata, duplicate IDs, invalid geometries, wrong acquisition times, incorrect cloud-cover values, missing thumbnails, and mismatched asset content.
Large catalog generation is slow: partition the catalog consistently, avoid rebuilding unchanged Items, and consider indexing or exposing the catalog through a STAC API rather than requiring clients to crawl every file. (github.com)
Next steps
Add domain-specific STAC extensions only where their fields improve discovery or interoperability, and validate those extensions in CI.
Create deterministic metadata-generation code from your source inventory rather than editing JSON by hand.
Publish versioned catalog releases and retain the source-data and processing versions used to create them.
Add automated HTTP checks for every published JSON document and a representative sample of data assets.
Build an index or STAC API when users need repeated spatial, temporal, collection, or property filtering over a large archive.
Connect STAC discovery to downstream geographic computation: retrieve assets intersecting a region or date range, then run raster, vector, environmental, or change-detection analysis on the selected data.
What you are building
A static STAC catalog is a set of JSON documents connected by links. The root Catalog points to child Catalogs, Collections, or Items. A Collection is appropriate when a group of Items shares higher-level metadata such as a license, provider, spatial extent, temporal extent, keywords, or summaries. An Item is the leaf-level record for an individual spatiotemporal asset and includes geometry, time, properties, links, and an assets dictionary. (github.com)
The distinction matters operationally. A Catalog can act like a navigable directory, while a Collection gives clients context about the dataset as a whole. For example, a catalog might contain a Collection for orthophotography, another for elevation products, and another for vegetation observations. Individual Items might represent one image scene, one tile, one point-cloud acquisition, or one dated observation. The correct unit depends on what users need to search, retrieve, and process.
- •Catalog: organizes and links related STAC resources.
- •Collection: describes a related set of Items with shared context.
- •Item: identifies one spatiotemporal asset and its metadata.
- •Asset: points to the downloadable or streamable data, thumbnail, mask, metadata file, or other supporting resource.
- •Link: expresses relationships such as self, root, parent, child, item, collection, or asset.
Prerequisites and design decisions
Before writing code, define the unit represented by an Item. For imagery, it may be one scene or tile. For repeated measurements, it may be one acquisition or observation. For point clouds, it may be one flight strip, tile, or collection of files. Avoid creating Items whose meaning changes from record to record; inconsistent granularity makes later search and comparison harder.
Choose a stable identifier policy. The STAC best-practices guidance recommends identifiers that are useful for discovery and compatible with filenames and links. Decide whether identifiers come from the source provider, a processing pipeline, a tile index, an acquisition timestamp, or a deterministic combination of those fields. Do not silently change IDs when regenerating metadata unless you are intentionally publishing a new version.
- •Python 3 and a virtual environment.
- •PySTAC for constructing and saving STAC objects.
- •A sample geographic asset with a durable path or URL.
- •A valid spatial extent and acquisition time for each Item.
- •A license, provider, and contact or provenance policy for the Collection.
- •A validation step in CI or before publication.
Step 1: create the environment and install tools
Create an isolated Python environment and install PySTAC. Pin the versions used by your production pipeline rather than allowing an unreviewed dependency update to change serialization or validation behavior.
- •The PySTAC documentation provides the Catalog, Collection, Item, layout, and save APIs used in this workflow. (pystac.readthedocs.io)
- •The STAC validation ecosystem includes tools for validating STAC JSON against the official schemas and for checking best practices. The validator project currently documents `stac-valid` as the PyPI package name while retaining the `stac-validator` command. (github.com)
Step 2: create a Collection and Item with PySTAC
The following example creates a Collection for a small set of aerial imagery and adds one Item. The geometry is written in GeoJSON coordinate order, longitude first and latitude second. The Item's `datetime` is expressed as an aware UTC datetime. The example uses a placeholder asset URL; replace it with a real object-storage or HTTP location.
- •A Collection requires meaningful spatial and temporal extents, a license, and descriptive metadata.
- •An Item should have a stable ID, a geometry, a bounding box, a UTC datetime, and an asset link.
- •Use the `data` role for the primary asset and `thumbnail` for a browse image when one exists. STAC recommends linking the main data file and commonly recommends a thumbnail for preview. (github.com)
Step 3: create the root Catalog and normalize the layout
After constructing the Collection and Item, attach the Collection to a root Catalog. PySTAC tracks self links and can normalize the HREFs for the entire tree according to a chosen layout strategy. The default best-practices layout creates conventional paths for the root catalog, collections, and items. PySTAC also supports template and custom layout strategies when a dataset needs a different partitioning scheme. (pystac.readthedocs.io)
Do not publish the in-memory object graph before setting its HREFs. A catalog can appear correct in Python while still containing missing or unresolved links. Normalize against the directory or URL root that will actually be published, then inspect the saved JSON files.
- •Use relative links when the catalog should be portable between environments.
- •Use absolute links when clients will consume the catalog from a fixed public location and the publication root is stable.
- •Keep asset URLs independent from local build paths.
- •If the archive is large, partition it consistently by collection, date, geography, or another searchable dimension.
- •Use link titles where helpful so clients can display readable names without opening every target document. (github.com)
Step 4: validate objects, links, assets, and semantics
Validation should happen at several levels. First validate the JSON against the STAC schema. Then validate extensions if you use them. Then check links and assets, including whether the referenced documents and data files can actually be retrieved. Finally run dataset-specific checks: geometry validity, ID uniqueness, time ordering, expected asset roles, file existence, content types, and consistency between Collection extents and the Items they contain.
The STAC validator documents single-file, batch, recursive, extension, link, and asset validation modes. The separate `stac-check` project adds linting based on STAC best practices, which can catch issues that are not necessarily schema failures, such as naming and layout choices. (github.com)
- •Schema validation: required fields, data types, and allowed structures.
- •Extension validation: fields declared by EO, projection, raster, scientific, view, or other extensions.
- •Link validation: self, root, parent, child, collection, item, and asset targets.
- •Asset validation: URL reachability, expected media type, permissions, and file integrity.
- •Geographic validation: valid geometry, bounding-box consistency, coordinate order, and expected CRS conventions.
- •Catalog validation: unique IDs, no broken relative paths, and consistent Collection extents.
Step 5: publish and operate the catalog
A static STAC catalog can be published from ordinary web hosting or object storage as long as clients can retrieve the linked JSON documents and assets. Treat the generated catalog as a versioned build artifact. Generate it from source metadata, validate it, publish it to a new release location, and promote that release only after link and asset checks pass.
Keep metadata generation separate from asset processing. A pipeline may transform imagery, generate cloud-optimized files, calculate thumbnails, or derive statistics in one stage, then create or update STAC Items in another. This separation makes it easier to identify whether a failure is in the geographic data, the asset file, or the catalog metadata.
- •Generate into a temporary directory.
- •Run schema, link, asset, and domain-specific checks.
- •Publish atomically or promote a versioned directory.
- •Record the source-data version and processing code version.
- •Monitor link failures and asset availability after publication.
- •Retain previous catalog releases when reproducibility matters.
Workflow
Install PySTAC and validation tools
Create an isolated environment and install the libraries used by the build and validation stages. Pin versions in a requirements file once the workflow is tested.
python -m venv .venv
source .venv/bin/activate # Windows: .venv\\Scripts\\activate
python -m pip install --upgrade pip
python -m pip install pystac stac-valid stac-checkCreate a Collection and Item
This example uses a single imagery Item. Replace the geometry, datetime, identifiers, properties, and asset href with values from your source dataset.
from datetime import datetime, timezone
from pathlib import Path
import pystac
from pystac import Asset, Collection, Extent, SpatialExtent, TemporalExtent
from shapely.geometry import mapping, box
root = Path("build/stac")
root.mkdir(parents=True, exist_ok=True)
bbox = [-122.52, 37.70, -122.35, 37.84]
geometry = mapping(box(*bbox))
collection = Collection(
id="example-aerial-imagery",
description="Example aerial imagery collection for a bounded study area.",
extent=Extent(
spatial=SpatialExtent([bbox]),
temporal=TemporalExtent([[datetime(2025, 1, 1, tzinfo=timezone.utc), datetime(2025, 12, 31, tzinfo=timezone.utc)]])
),
license="proprietary",
title="Example Aerial Imagery",
keywords=["aerial imagery", "orthophoto"],
providers=[pystac.Provider(name="Example Data Group", roles=["producer", "processor"])]
)
item = pystac.Item(
id="example-aerial-2025-06-01-001",
geometry=geometry,
bbox=bbox,
datetime=datetime(2025, 6, 1, 15, 30, tzinfo=timezone.utc),
properties={
"platform": "example-aircraft",
"gsd": 0.25
}
)
item.add_asset(
"image",
Asset(
href="https://example.org/assets/example-aerial-2025-06-01-001.tif",
media_type="image/tiff; application=geotiff; profile=cloud-optimized",
roles=["data"],
title="Cloud-optimized GeoTIFF"
)
)
item.add_asset(
"thumbnail",
Asset(
href="https://example.org/assets/example-aerial-2025-06-01-001.jpg",
media_type="image/jpeg",
roles=["thumbnail"],
title="Preview image"
)
)
collection.add_item(item)Create the root Catalog and save it
Attach the Collection to a root Catalog, normalize the links against the intended publication directory, and save the catalog as a self-contained static tree.
catalog = pystac.Catalog(
id="example-geospatial-catalog",
description="STAC catalog for example geographic assets.",
title="Example Geospatial Catalog"
)
catalog.add_child(collection)
catalog.normalize_and_save(
root_href=str(root),
catalog_type=pystac.CatalogType.SELF_CONTAINED
)
print(f"Wrote STAC catalog to {root / 'catalog.json'}")Inspect the generated files
Confirm that the expected documents exist and inspect the links before publishing.
find build/stac -type f -name '*.json' -print
python -m json.tool build/stac/catalog.json >/dev/null
python -m json.tool build/stac/example-aerial-imagery/collection.json >/dev/nullValidate the catalog and its linked resources
Run schema validation first, then recursive, link, asset, and best-practice checks as appropriate for your release.
stac-validator validate build/stac/catalog.json --recursive --links --assets
stac-check build/stac/catalog.json --recursiveQuestions teams ask
Should I create a Catalog or a Collection?
Use a Catalog for hierarchical organization and browsing. Use a Collection when the grouped Items share dataset-level metadata such as license, provider, keywords, spatial extent, temporal extent, or summaries. In many production datasets, a root Catalog contains one or more Collections, and each Collection links to its Items. (github.com)
What should one STAC Item represent?
Choose a stable unit that users will want to discover and process independently: for example, one image scene, tile, acquisition, point-cloud strip, or dated observation. The specification does not force one universal granularity, but inconsistent Item meaning within the same Collection makes search and downstream processing harder.
Do STAC Items have to contain the data itself?
No. An Item contains metadata and links to assets. Assets may be local relative files, HTTP resources, object-storage URLs, streaming services, thumbnails, masks, or supporting metadata. The links must remain valid and meaningful for the intended consumers. (github.com)
Is a static STAC catalog enough for spatial search?
It can be enough for small catalogs or clients that crawl the link graph, but large or frequently queried datasets generally need an index or a STAC API. A STAC API adds dynamic retrieval and filtering of Items and other resources; it does not eliminate the need for correct underlying STAC metadata. (github.com)
What is the most common production mistake?
Publishing metadata whose links do not match the final deployment location. Generate and inspect the catalog using the same root layout that will be published, normalize HREFs before saving, and test both the JSON documents and the referenced assets.
Keep exploring
convert geojson with gdal production guide
A STAC Item often points to vector or raster assets that must first be converted, reprojected, or validated. This guide covers the adjacent data-preparation stage.
analyze spatial data with geopandas production guide
After discovering and retrieving STAC-linked geographic assets, GeoPandas can support vector inspection, spatial joins, measurements, and validation.
Sources
STAC Specification: Overview
Defines how Catalogs, Collections, and Items relate and explains the role of GeoJSON, links, metadata, and extensions.
Open sourceSTAC Catalog Specification
Documents required Catalog fields, link relationships, media type, and the discovery purpose of a Catalog.
Open sourceSTAC Item Specification
Documents Item geometry, datetime, collection links, assets, and recommended metadata.
Open sourceSTAC Best Practices
Provides guidance for static catalog layout, filenames, identifiers, links, and partitioning.
Open sourcePySTAC Documentation
Provides the Python APIs for creating, linking, laying out, normalizing, and saving STAC objects.
Open sourceSTAC Validator
Documents schema, recursive, extension, link, asset, batch, and command-line validation workflows.
Open sourcestac-check
Adds best-practice linting and additional checks beyond core schema validation.
Open sourceSTAC API Specification
Explains the dynamic API layer for retrieving and filtering STAC resources.
Open source