Develop & Contribute¶
Prerequisites¶
We recommend using uv as the project manager for development.
See docs.astral.sh/uv/getting-started/installation/ for installation.
Install & Test¶
# Clone the repository
git clone https://github.com/stac-utils/stac-fastapi.git
cd stac-fastapi
# Install dependencies (dev + runtime)
uv sync --dev
# Run tests to confirm everything works
uv run pytest
If all tests pass, your environment is ready.
Local Documentation¶
stac-fastapi uses MkDocs-Material. Build or serve docs with uv.
# Static build (output → ./site)
uv run --group docs mkdocs build -f docs/mkdocs.yml
# Live‑reload dev server
uv run --group docs mkdocs serve -f docs/mkdocs.yml --livereload
Manual docs deployment
If you need to manually deploy docs, run:
uv run --group docs mkdocs gh-deploy -f docs/mkdocs.yml
Note that you should never need to do this because GitHub Actions deploys automatically for new commits.
Create Custom Extensions¶
STAC FastAPI embeds many API extensions. But if you need to add deployment-specific routes (e.g., custom analytics, map tiles, or proprietary workflows) to your STAC API, you can build custom extensions without forking or modifying the core repository.
The framework is designed to seamlessly mount external routes alongside the standard endpoints and include them in the OpenAPI schema.
1. Define the Extension¶
Create a class that inherits from stac_fastapi.types.extension.ApiExtension and bind your FastAPI routes inside the register() method:
from fastapi import APIRouter
from stac_fastapi.types.extension import ApiExtension
class MyCustomExtension(ApiExtension):
"""Example of a custom out-of-tree extension."""
def register(self, app):
router = APIRouter()
@router.get("/api/custom-route")
async def my_route():
return {"message": "Hello from my custom extension!"}
app.include_router(router)
2. Inject it into your Backend¶
Modern stac-fastapi backends (such as pgstac and elasticsearch-opensearch) utilize a factory pattern (instantiate_api) that accepts custom extensions. Depending on the backend's implementation, you can typically inject your custom class into the application during startup via an extra_map or an extensions array.
For a comprehensive, real-world example of wiring routes, models, and dependencies in a standalone extension, see the Multi-Tenant Catalogs extension.
Response Validation¶
A common question when using this package is how request and response types are validated?
This package uses stac-pydantic to validate and document STAC objects. However, by default, validation of response types is turned off and the API will simply forward responses without validating them against the Pydantic model first. This decision was made with the assumption that responses usually come from a (typed) database and can be considered safe. Extra validation would only increase latency, in particular for large payloads.
To turn on response validation, set ENABLE_RESPONSE_MODELS to True. Either as an environment variable or directly in the ApiSettings.
With the introduction of Pydantic 2, the extra time it takes to validate models became negatable. While ENABLE_RESPONSE_MODELS still defaults to False there should be no penalty for users to turn on this feature but users discretion is advised.
Contributing¶
Contributions are welcome! Feel free to open an issue in order to discuss changes before offering a Pull Request.
Setting up pre‑commit locally¶
This repo is set to use pre-commit to run ruff, pydocstring and mypy when committing new code.
# Install the Git hook
uv run pre-commit install
# Run all checks manually (optional)
uv run pre-commit run --all-files
Release Process¶
This is a checklist for releasing a new version of stac-fastapi.
- Determine the next version. We currently do not have published versioning guidelines, but there is some text on the subject here: radiantearth/stac-spec?1184.
- Create a release branch named
release/vX.Y.Z, whereX.Y.Zis the new version. -
Search and replace all instances of the current version number with the new version. As of this writing, there's 3 different
version.pyfiles, and oneVERSIONfile, in the repo.Note: You can use
bump-my-versionCLIuv run --with bump-my-version bump-my-version bump --new-version 3.1.0 -
Update CHANGES.md for the new version. Add the appropriate header, and update the links at the bottom of the file.
- Audit CHANGES.md for completeness and accuracy. Also, ensure that the changes in this version are appropriate for the version number change (i.e. if you're making breaking changes, you should be increasing the
MAJORversion number). - (optional) If you have permissions, run
scripts/publish --testto test your PyPI publish. If successful, the published packages will be available on test.pypy.org. - Push your release branch, create a PR, and get approval.
- Once the PR is merged, create a new (annotated, signed) tag on the appropriate commit. Name the tag
X.Y.Z, and includevX.Y.Zas its annotation message. - Push your tag to Github, which will kick off the publishing workflow.
- Create a new release targeting the new tag, and use the "Generate release notes" feature to populate the description. Publish the release and mark it as the latest.