Home
Open a lazy (time, band, y, x) xarray DataArray from thousands of cloud-optimized GeoTIFFs. No GDAL required.
<xarray.DataArray (band: 3, time: 121, y: 7100, x: 13000)> Size: 67GB
[33504900000 values with dtype=int16]
Coordinates:
* band (band) <U5 60B 'red' 'green' 'blue'
* time (time) datetime64[s] 968B 2025-06-01 2025-06-02 ... 2025-09-30
* y (y) float64 57kB 2.22e+06 2.22e+06 2.22e+06 ... 2.93e+06 2.93e+06
* x (x) float64 104kB -7e+05 -6.998e+05 -6.998e+05 ... 5.998e+05 6e+05
Attributes:
_stac_backend: MultiBandStacBackendArray(bands=['red', 'green', 'blu...
_stac_time_coords: 2025-06-01 … 2025-09-30 (n=121)What is lazycogs?¶
lazycogs lets you materialize a lazy xarray DataArray view of massive STAC-indexed data archives in any CRS and resolution. Opening the array is nearly instant because no COGs are read until you request pixels. lazycogs queries the stac-geoparquet dataset using rustac to find only the COGs that intersect a spatial and temporal selection, fetches only the relevant pixel windows using async-geotiff, and reprojects into your target grid.
Note: lazycogs only reads GeoTIFFs. If your assets are in another format, lazycogs is not the right tool.
Here is a summary of the libraries lazycogs uses for each step:
| Task | Library |
|---|---|
| STAC search + spatial indexing | rustac (DuckDB + geoparquet) |
| COG I/O | async-geotiff (Rust, no GDAL) |
| Cloud storage | obstore |
| Reprojection | pyproj + numpy |
| Lazy dataset construction | xarray BackendEntrypoint + LazilyIndexedArray |
Installation¶
Not yet published to PyPI. Install directly from GitHub:
Minimal example¶
import lazycogs
import rustac
from pyproj import Transformer
dst_crs = "EPSG:5070"
dst_bbox = (-400_000, 2_500_000, -200_000, 2_700_000)
transformer = Transformer.from_crs(dst_crs, "epsg:4326", always_xy=True)
bbox_4326 = transformer.transform_bounds(*dst_bbox)
# Search a STAC API and cache results to a local stac-geoparquet file.
await rustac.search_to(
"items.parquet",
"https://earth-search.aws.element84.com/v1",
collections=["sentinel-2-c1-l2a"],
datetime="2025-06-01/2025-08-31",
bbox=bbox_4326,
)
# Open a fully lazy (time, band, y, x) DataArray. No COGs are read yet.
da = lazycogs.open(
"items.parquet",
bbox=dst_bbox,
crs=dst_crs,
resolution=10.0,
)
Get started with the Quickstart. Evaluating lazycogs against alternatives? See Performance.