Create a STAC catalog: a practical guide to organizing geospatial assets

A STAC catalog is a structured set of JSON documents that makes geospatial assets easier to discover, browse, and connect to the files they describe. This guide shows how to build a small catalog with PySTAC, decide when to use a Catalog or Collection, create Items with spatial and temporal metadata, attach assets, normalize links, save a portable layout, and validate the result. It also explains what a static STAC catalog does not provide: it is not automatically a search API, processing engine, raster format, or replacement for the underlying data store.

The SpatioTemporal Asset Catalog, or STAC, provides a common structure for describing geospatial information so it can be indexed, discovered, and used by software. Its core objects are deliberately small: an Item represents an individual spatiotemporal asset, a Catalog organizes links to Items and other catalogs, and a Collection adds metadata about a related group of Items. STAC began with imagery but is also used for data such as point clouds, lidar, elevation models, vector data, machine-learning labels, mosaics, and other Earth-observation products. (ogc.org) This guide builds a static catalog in Python. The workflow is useful whether your assets are GeoTIFFs, cloud-optimized rasters, point-cloud files, vector extracts, model outputs, or derived products. The central discipline is to keep three things distinct: the metadata describing an asset, the link to the physical asset, and the application that later searches or computes over that asset.

How EDK fits

For: This guide is for GIS developers, remote-sensing engineers, data-platform teams, and analysts who need to publish a small or medium-sized set of geospatial assets in a standards-based structure. It assumes basic Python, JSON, GeoJSON geometry, and familiarity with URLs or object-storage paths.

STAC is relevant to the physical-world computing problem because it gives geospatial assets a consistent identity, footprint, time range, and set of links. That makes otherwise scattered observations—such as imagery, elevation products, road extracts, environmental measurements, or derived change-detection outputs—easier to find and relate to real places. The connection is complementary rather than substitutive: STAC describes and organizes assets; it does not itself provide a complete world model, universal place search, routing engine, spatial database, or arbitrary geographic computation. In a broader world-model workflow, a STAC catalog can serve as a discoverable source layer whose Items are filtered by location and time, inspected for provenance, and then combined with other physical-world features for measurement, comparison, change analysis, or regional aggregation.

  • •Catalog satellite scenes, aerial imagery, elevation tiles, lidar files, or derived environmental products so applications can find assets by footprint and acquisition time before loading the underlying files.
  • •Publish versioned geospatial outputs—such as change-detection rasters, road-condition observations, vegetation products, or infrastructure inventories—with explicit asset links and metadata that downstream geographic systems can compare, filter, and analyze.
  • •Use STAC metadata as an inventory boundary around a larger location-data workflow: discover candidate assets for a city, watershed, road corridor, or other region, then perform the actual spatial computation in a GIS, database, raster engine, or world-model system.
Core specification
STAC Community Standard 1.1.0 is listed by OGC alongside STAC API 1.0.0. (ogc.org)
Core objects
Catalog, Collection, Item, and Asset
Typical Item form
A GeoJSON Feature with spatial, temporal, link, and asset metadata
Primary implementation used here
PySTAC for Python-based creation, layout, and serialization
Static versus dynamic
A static catalog is a linked JSON structure; a STAC API adds HTTP discovery and search behavior.

The EDK outcome

Before you start

Python 3 and basic familiarity with virtual environments, JSON, and GeoJSON.

A clear definition of what one STAC Item represents in your dataset.

A stable identifier policy for Catalogs, Collections, and Items.

A valid footprint or bounding box for each spatial asset.

A defensible temporal model, including acquisition, observation, or coverage intervals.

A durable location for each underlying asset and a decision about relative versus absolute links.

Licensing, provider, provenance, and access information for the data being published.

Learning objectives

Distinguish a STAC Catalog, Collection, Item, and Asset.

Create a basic STAC catalog in Python with PySTAC.

Attach spatial, temporal, provenance, and asset metadata to an Item.

Normalize and save a portable or published catalog layout.

Validate the catalog recursively and test real asset links.

Recognize when a static catalog should be complemented by a STAC API or another search and computation system.

Verification

The root document declares a supported stac_version and has the correct object type.

Every Catalog, Collection, and Item has a stable identifier and usable links.

Each Item has geometry and bbox values that agree with the actual asset footprint.

Temporal properties are valid UTC timestamps or correctly modeled intervals.

Each Asset link points to the intended file, service, thumbnail, or metadata document.

The declared media type, roles, title, license, provider, and extension fields are accurate.

The saved catalog works from its final filesystem or web URL, not only from the development directory.

Recursive validation completes at the intended depth, and link or asset checks produce no unexplained failures.

Troubleshooting

Missing or null HREFs: objects created in memory do not yet know where they will be saved. Call normalize_hrefs with the intended root directory before calling save.

Broken relative links after publishing: check the path from each Item JSON file to catalog.json, Collections, and assets. A relative asset path is resolved from the Item’s location, not necessarily from the catalog root.

Invalid geometry or bbox: verify GeoJSON coordinate order, ring closure, longitude and latitude ranges, and whether the footprint actually describes the asset rather than the processing tile or source scene.

Datetime validation errors: use timezone-aware UTC datetimes and do not use a single instant when the asset represents a meaningful interval. Model start and end properties where appropriate.

A valid catalog that cannot be consumed: inspect media types, asset roles, file permissions, redirects, signed URL expiration, and whether the asset remains available at the published URL.

Extension errors: declare every extension used by the Item or Collection and confirm that its fields follow the matching extension specification. Remove experimental fields if the consumer only supports core STAC.

Catalog is too slow to browse: avoid placing an enormous number of direct Item links in one root document. Organize Items through meaningful subcatalogs or Collections, then consider a STAC API or indexed backend for interactive search.

Validation passes but results are semantically wrong: schema validation cannot determine whether a footprint, timestamp, license, processing level, or provider statement is truthful. Add domain-specific tests and review representative Items against the underlying files.

Next steps

Add a Collection with spatial and temporal extents, license, keywords, providers, and a product description.

Choose and document extensions for domain-specific fields such as raster metadata, processing metadata, electro-optical properties, scientific data, or projection information.

Build a release pipeline that generates the catalog from a versioned manifest and validates it before publication.

Expose the catalog through a STAC API when users need dynamic spatial, temporal, or property-based search.

Connect selected STAC assets to the appropriate downstream system for raster analysis, vector processing, geographic indexing, visualization, or physical-world computation.

What you are building—and what STAC does not do

A minimal STAC Catalog is a JSON document with a STAC version, object type, identifier, description, and links. Its links lead to child Catalogs, Collections, or Items. The structure is intentionally flexible: catalogs can be organized by date, geography, provider, product family, processing version, or another meaningful hierarchy. The STAC tutorial describes a Catalog as a starting point for navigating a tree of STAC objects, rather than as a rigid database schema. (stacspec.org)

An Item is the atomic record for an asset or inseparable group of assets. It uses a GeoJSON Feature shape and normally includes an identifier, geometry, bounding box, temporal properties, links, and an assets object. The Asset entries point to the files or services that users actually want to download or read. For example, one imagery Item might expose a primary GeoTIFF, a thumbnail, a cloud-optimized copy, and a metadata document as separate assets.

  • •Good fit: static publishing, object-storage inventories, dataset exchange, reproducible releases, and machine-readable discovery.
  • •Not sufficient by itself: raster processing, vector analysis, routing, geocoding, authentication, data transformation, or high-volume interactive search.
  • •STAC metadata should describe the underlying asset accurately; it should not imply that the catalog contains a copy of the asset.

Prerequisites and design decisions

Before writing code, identify the assets you will publish and decide what one Item represents. For imagery, an Item often represents one scene at one acquisition time, while individual bands or representations become Assets. For a time series, an Item might represent one observation date. For a derived product, it might represent one tile, one model run, or one processing result. The correct granularity depends on how users will search, compare, and consume the data.

You also need a stable identifier policy. Item identifiers should remain stable when the underlying observation or product has not changed. If a new processing version creates a materially different product, encode that distinction in the identifier or in documented properties. Avoid generating identifiers from temporary filenames or local directory paths.

  • •Python 3 and a virtual environment.
  • •The PySTAC package for creating and writing STAC objects.
  • •A footprint or bounding box for each Item.
  • •An asset location, such as a local path, HTTPS URL, or object-storage URL.
  • •A license and provenance policy for the data you are publishing.
  • •Optional: stac-validator for recursive validation of catalogs, Items, Collections, links, and assets.

Step 1: install PySTAC and create the catalog

PySTAC is a Python library for reading and writing STAC objects. The basic workflow is to create a Catalog, create one or more Items, attach Assets, add the Items to the Catalog or Collection, normalize the file layout, and save the result. PySTAC’s tutorial documents this in-memory-to-filesystem workflow and explains that normalization sets the self links used when saving objects. (stacspec.org)

  • •Create an isolated environment and install the library:

Step 2: create an Item with geometry, time, and an asset

The following example creates a small catalog for one geospatial file. The geometry is a simple polygon footprint; replace it with the actual footprint of your asset. The example uses an HTTPS asset URL, but the same field can point to a local file or object-storage location.

  • •Use a UTC datetime and attach descriptive metadata:

Step 3: add a Collection when the dataset has shared metadata

A Collection is useful when all Items belong to a known product family or dataset. It lets you put shared information—such as license, providers, keywords, and overall spatial or temporal extents—at the collection level instead of duplicating it on every Item. Items still need their own geometry, temporal information, identifiers, and assets.

For a catalog containing many unrelated products, create multiple Collections under one root Catalog. For a single homogeneous dataset, one Collection under a root Catalog is often enough. This structure also gives future API implementations a natural unit for discovery and filtering.

  • •Use a Collection when users will ask questions such as: which observations belong to this product, who produced them, what license applies, or what time and geographic range does the dataset cover?
  • •Use a plain Catalog for navigation when the children are primarily other catalogs or collections and there is no single shared dataset description.

Step 4: normalize links and save a publishable layout

Objects created in memory do not automatically have useful self links. Call normalize_hrefs with a root directory before saving. PySTAC then assigns predictable paths such as catalog.json at the root and an Item JSON file below an Item-specific directory. The official tutorial demonstrates both self-contained catalogs with relative links and absolute-published catalogs with absolute links. (stacspec.org)

For a portable archive, use relative links and keep the catalog JSON files together. For a public deployment, absolute links can make the catalog independent of its serving location, but they require a stable publishing domain or object-storage namespace. Do not mix assumptions casually: a catalog that works on a local filesystem may fail when uploaded if asset links point to local paths.

  • •A typical save sequence is:
  • •After saving, inspect catalog.json and at least one Item JSON manually. Confirm that root, parent, collection, item, and self links point to the intended locations.
  • •If assets should be relative to the Item file, make the asset HREFs relative before saving. Otherwise, preserve absolute URLs for a deliberately published catalog.

Step 5: validate the catalog and test the real links

Validation should happen before publication and in continuous integration. The STAC specification provides schemas for its core objects and extensions, while stac-validator can validate Items, Collections, and Catalogs and can recursively inspect related objects. Its command-line options include recursive traversal, link validation, asset validation, extension checks, and maximum-depth controls. (stac-validator.readthedocs.io)

Schema validation is necessary but not sufficient. Also test that every asset URL resolves, every geometry is valid for the intended footprint, every timestamp is parseable, the declared license is accurate, and the published data has the permissions and retention characteristics users expect. A catalog can be structurally valid while pointing to expired signed URLs, private buckets, moved files, or assets with the wrong coordinate reference system.

  • •Example validation command:
  • •Check both the root catalog and a representative Item directly.
  • •If you use extensions, ensure the extension identifiers are declared and that extension fields follow the relevant extension specification.

Operating the catalog as the dataset grows

A small static catalog can be served from ordinary web hosting or object storage. As the number of Items grows, the filesystem tree and JSON traversal model may become less convenient for users and applications. At that point, consider exposing the same STAC objects through a STAC API or indexing the metadata in a purpose-built catalog service. STAC API supports browsing and querying Items and Collections, including search across collections, while keeping STAC Items as the returned geographic records. (docs.ogc.org)

Keep the publishing process reproducible. Generate catalog files from a source manifest, record the source-data version and processing version, and publish a release atomically so that the root catalog does not point to a mixture of old and new files. If assets are immutable, content-addressed, or versioned, say so in your documentation. If assets can change in place, document that too, because a stable Item identifier does not guarantee stable bytes.

  • •Start with static STAC when publishing and portability matter more than interactive query.
  • •Add a STAC API when users need dynamic spatial, temporal, or property filtering.
  • •Keep processing and analysis outside the catalog layer unless you are deliberately integrating a separate raster, vector, database, or workflow system.

Workflow

01

Install the minimum tooling

Create a virtual environment and install PySTAC. Add stac-validator when you want command-line validation and recursive link or asset checks.

python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install pystac stac-validator
02

Create a Catalog and Item

The Item below represents one geospatial asset with a polygon footprint and an acquisition timestamp. Replace the example geometry and URL with values derived from the actual file.

from datetime import datetime, timezone
import pystac

catalog = pystac.Catalog(
    id="example-earth-observations",
    description="Example catalog of geospatial observations"
)

footprint = {
    "type": "Polygon",
    "coordinates": [[
        [-122.52, 37.70],
        [-122.52, 37.82],
        [-122.35, 37.82],
        [-122.35, 37.70],
        [-122.52, 37.70]
    ]]
}

item = pystac.Item(
    id="observation-2026-01-15",
    geometry=footprint,
    bbox=[-122.52, 37.70, -122.35, 37.82],
    datetime=datetime(2026, 1, 15, 18, 30, tzinfo=timezone.utc),
    properties={
        "processing:level": "L2"
    }
)

item.add_asset(
    key="data",
    asset=pystac.Asset(
        href="https://example.org/assets/observation-2026-01-15.tif",
        media_type="image/tiff; application=geotiff",
        roles=["data"],
        title="Observation raster"
    )
)

catalog.add_item(item)
03

Normalize the layout and save

Normalize HREFs before saving so PySTAC can assign predictable self, parent, root, and item links. Use relative links for a portable directory or absolute links for a deliberately published catalog.

from pathlib import Path

output_dir = Path("build/stac")
catalog.normalize_hrefs(str(output_dir))
catalog.save(catalog_type=pystac.CatalogType.SELF_CONTAINED)

print(catalog.get_self_href())
print(item.get_self_href())
04

Validate the root and linked objects

Run structural validation and, where appropriate, recursive link and asset checks. Treat failures involving external URLs separately from schema failures so that unavailable services do not hide invalid metadata.

stac-validator build/stac/catalog.json
stac-validator --recursive --links --assets build/stac/catalog.json
05

Publish and test from the real deployment location

Upload the complete directory or publish the generated JSON documents at their final URLs. Then request catalog.json and a representative Item through the public path, inspect the links, and verify that each Asset URL resolves with the expected content type and access policy.

curl -I https://example.org/stac/catalog.json
curl -s https://example.org/stac/catalog.json | python -m json.tool

Questions teams ask

Should I create a Catalog or a Collection?

Use a Catalog primarily as a navigation structure. Use a Collection when a group of Items represents a coherent dataset or product family with shared metadata such as license, provider, keywords, spatial extent, or temporal extent. A common arrangement is one root Catalog containing one or more Collections, with Items inside each Collection. (stacspec.org)

Does a STAC catalog contain the raster or vector data itself?

Usually no. A STAC Item contains metadata and Asset links that identify the physical files or services. The catalog can point to GeoTIFFs, cloud-optimized rasters, point-cloud files, vector datasets, thumbnails, documentation, or alternate representations. The linked asset remains a separate object that must be hosted and permissioned correctly.

Can I search a static STAC catalog by bounding box and date?

A static catalog provides linked JSON documents that can be crawled or read, but it does not by itself define a query engine. For dynamic spatial and temporal search, expose the catalog through a STAC API or index the metadata in another service. STAC API defines search behavior and endpoints for retrieving STAC objects and Items. (docs.ogc.org)

Do all STAC Items need a geometry?

An Item is designed to describe a spatial asset and normally includes geometry and a bounding box. If the source has an unusual or unavailable footprint, follow the applicable STAC specification and document the limitation rather than fabricating geometry. The geometry must represent the asset honestly enough for spatial discovery and downstream interpretation.

Which validation tool should I use?

Use the STAC schemas and a validator that supports the STAC version and extensions you publish. The stac-validator CLI can validate core objects, recursively traverse linked objects, and optionally check links and assets. Add project-specific tests for URL availability, geometry quality, timestamp semantics, licensing, and expected file formats. (stac-validator.readthedocs.io)

Keep exploring

Sources

More in Guides