Skip to content

Build surface fuel grids from LANDFIRE

You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.

LANDFIRE supplies several categorical descriptions of surface fuels. FastFuels fetches the classification for your domain, then uses that product’s lookup table to produce the continuous load, depth, and surface-area-to-volume bands your workflow needs. Every product follows the same two-step pattern: fetch a classification grid, then run a lookup against it.

Maps of the same Santa Fe area. The left map contains discrete LF2024 FBFM40 classes and a categorical legend. The right map shows the continuous 1-hour fuel load produced by looking up each class, with a scale from 0 to 1.3 kilograms per square metre.

A categorical FBFM40 cell stores a fuel-model code. The lookup replaces that code with the physical parameter assigned to the model; this example shows fuel_load.1hr in kg/m². Reusing the classification lets you request other parameters without fetching LANDFIRE again.

ProductUse it when you needCategorical bandRepresentative lookup output
Annual FBFM40Scott and Burgan’s 40 fire-behavior fuel models for a landscape vintagefbfmDead timelag and live herbaceous/woody loads, SAVR, fuel depth
Seasonal FBFM40A published seasonal condition layer rather than the annual FBFM40 baselinefbfmThe same FBFM40 parameter vocabulary
FBFM13Anderson’s 13 fire-behavior fuel modelsfbfm13Dead timelag and live foliage loads, SAVR, fuel depth
FCCSFuelbeds with litter, duff, shrub, herb, and woody componentsfccsLitter and duff loads, duff depth, live and dead loads

These products classify the landscape under different systems. Their numeric codes are identifiers within each system, not interchangeable fuel-load values.

Three maps of the same Santa Fe detail showing LF2024 FBFM40 codes, LF2024 FBFM13 codes, and LF2023 FCCS fuelbed IDs. Each map has its own categorical legend and spatial pattern.

FBFM40, FBFM13, and FCCS over the same 1.5 km square. Each panel has its own legend because a code only has meaning within its classification system. The product versions are shown in the panel titles.

Each product is available at one or more LANDFIRE landscape vintages. Some vintages are served from pre-built national rasters and return quickly; the current-year vintage is fetched on demand from the LANDFIRE Product Service (LFPS) and takes longer, with coverage that varies by region. Not every product has every vintage — FCCS, for instance, has one pre-built vintage (2023) and the on-demand 2025. The coverage check at the end of this guide shows how to see exactly which versions and seasons are available for your domain.

  1. An API key: my-api-key.

  2. A domain within LANDFIRE coverage: your-domain-id. See Create a domain.

POST fbfm40/landfire
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/fbfm40/landfire' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Annual FBFM40 — LF2024",
"version": "2024"
}'

version is the LANDFIRE landscape vintage — the snapshot of the landscape that LANDFIRE modeled. The response reports the calendar year the data represents as source.year; for an annual grid the two match. This example requests LF2024, a pre-built vintage that returns quickly. Record the id as your-fbfm40-grid-id. Set your-grid-id to that value when polling:

Set remove_non_burnable: true in the fetch request when non-burnable FBFM40 classes should become nodata rather than remain classification codes.

Poll until completed:

GET grid status
curl -X 'GET' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/your-grid-id' \
-H 'accept: application/json' \
-H 'api-key: my-api-key'

Translate the codes into physical parameters

Section titled “Translate the codes into physical parameters”

Point the lookup at the completed FBFM grid. source_band is the band holding the codes (fbfm), and bands is the list of parameters to compute.

POST lookup/fbfm40
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/lookup/fbfm40' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Annual FBFM40 surface parameters",
"source_grid_id": "your-fbfm40-grid-id",
"source_band": "fbfm",
"bands": [
"fuel_load.1hr",
"fuel_load.10hr",
"fuel_load.100hr",
"fuel_load.live_herb",
"fuel_load.live_woody",
"fuel_depth"
]
}'

Record this id as your-lookup-grid-id and poll it to completed. The output bands are continuous and carry their units:

{
"id": "your-lookup-grid-id",
"domain_id": "your-domain-id",
"name": "Annual FBFM40 surface parameters",
"description": "",
"status": "completed",
"progress": {
"percent": 100,
"message": "Complete"
},
"created_on": "2026-08-24T22:40:44.648414Z",
"modified_on": "2026-08-24T22:40:47.344970Z",
"checksum": "401c1e67aeb94c68bb77ffb6ce4e9451",
"source": {
"source_grid_id": "your-fbfm40-grid-id",
"source_grid_checksum": "0917d07ab25b4a978727fa2ed059665f",
"source_band": "fbfm",
"name": "lookup",
"table": "fbfm40"
},
"modifications": [],
"bands": [
{
"key": "fuel_load.1hr",
"name": "1-hour Fuel Load",
"description": "Oven-dry mass per unit area of 1-hour timelag dead fuels.",
"type": "continuous",
"unit": "kg/m**2",
"index": 0,
"nodata": null,
"summary": {
"type": "continuous",
"count": 11227,
"nodata_count": 0,
"min": 0.0,
"max": 1.3001821041107178,
"mean": 0.28268456370417544,
"std": 0.2866704442804344
}
},
{
"key": "fuel_load.10hr",
"name": "10-hour Fuel Load",
"description": "Oven-dry mass per unit area of 10-hour timelag dead fuels.",
"type": "continuous",
"unit": "kg/m**2",
"index": 1,
"nodata": null,
"summary": {
"type": "continuous",
"count": 11227,
"nodata_count": 0,
"min": 0.0,
"max": 1.1880974769592285,
"mean": 0.4447985170375072,
"std": 0.4233805556614999
}
},
{
"key": "fuel_load.100hr",
"name": "100-hour Fuel Load",
"description": "Oven-dry mass per unit area of 100-hour timelag dead fuels.",
"type": "continuous",
"unit": "kg/m**2",
"index": 2,
"nodata": null,
"summary": {
"type": "continuous",
"count": 11227,
"nodata_count": 0,
"min": 0.0,
"max": 0.9863450527191162,
"mean": 0.36682045139877373,
"std": 0.3905496454864779
}
},
{
"key": "fuel_load.live_herb",
"name": "Live Herbaceous Fuel Load",
"description": "Oven-dry mass per unit area of live herbaceous fuels.",
"type": "continuous",
"unit": "kg/m**2",
"index": 3,
"nodata": null,
"summary": {
"type": "continuous",
"count": 11227,
"nodata_count": 0,
"min": 0.0,
"max": 0.22416932880878448,
"mean": 0.04757333884200335,
"std": 0.06454520602446025
}
},
{
"key": "fuel_load.live_woody",
"name": "Live Woody Fuel Load",
"description": "Oven-dry mass per unit area of live woody fuels.",
"type": "continuous",
"unit": "kg/m**2",
"index": 4,
"nodata": null,
"summary": {
"type": "continuous",
"count": 11227,
"nodata_count": 0,
"min": 0.0,
"max": 0.8630518913269043,
"mean": 0.23526099223586802,
"std": 0.2852485708917369
}
},
{
"key": "fuel_depth",
"name": "Fuel Bed Depth",
"description": "Vertical depth of the surface fuel bed.",
"type": "continuous",
"unit": "m",
"index": 5,
"nodata": null,
"summary": {
"type": "continuous",
"count": 11227,
"nodata_count": 0,
"min": 0.0,
"max": 1.8287999629974365,
"mean": 0.5720015678488742,
"std": 0.6444623598459112
}
}
],
"georeference": {
"crs": "EPSG:32613",
"transform": [
29.92571976224661, 0.0, 416700.0, 0.0, -29.925719762248104,
3948562.3491355116
],
"shape": [103, 109]
},
"error": null,
"chunks": {
"shape": [512, 512],
"count": 1,
"count_by_axis": {
"x": 1,
"y": 1
}
},
"tags": []
}

This is the finished annual surface-fuel grid: every cell’s FBFM40 code is mapped to the requested load, depth, or SAVR values.

A seasonal request adds season to FBFM40. version remains the landscape vintage, but source.year now reflects the calendar year the seasonal layer represents — typically one year ahead of the vintage. In this example, version: "2025" with season: "SU" returns year: 2026 because the data describes summer 2026 conditions. Seasonal layers are always fetched on demand from LFPS, so they take longer than a pre-built annual request and their availability depends on which regions and seasons LANDFIRE has published.

Side-by-side maps of the common Santa Fe footprint. The left map is annual FBFM40 for LF2024; the right is the LF2025 SU26 layer for summer 2026. Both panels use the same categorical colors and shared legend.

Annual LF2024 and summer LF2025 SU26 over their common extent. Both are FBFM40 classifications and therefore share a legend. In this live example, 47.9% of cells in the common footprint have different codes.

The alignment object uses the annual grid as the target. Keep the two source grid ids separate: the lookup must point to the classification whose conditions you want.

POST seasonal fbfm40/landfire
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/fbfm40/landfire' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Summer 2026 FBFM40 — LF2025 SU26",
"version": "2025",
"season": "SU",
"alignment": {
"target": "grid",
"grid_id": "your-fbfm40-grid-id"
}
}'

Record the id as your-seasonal-fbfm40-grid-id. Inspect the completed grid’s georeference before cell-by-cell comparison; product coverage can add or omit an edge row even when an alignment target is supplied.

The lookup endpoint and band vocabulary do not change. Only source_grid_id changes to the seasonal classification.

POST lookup/fbfm40 for SU26
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/lookup/fbfm40' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Summer 2026 FBFM40 surface parameters",
"source_grid_id": "your-seasonal-fbfm40-grid-id",
"source_band": "fbfm",
"bands": [
"fuel_load.1hr",
"fuel_load.live_herb",
"fuel_load.live_woody",
"fuel_depth"
]
}'

Record the result as your-seasonal-lookup-grid-id.

FBFM13 follows the same fetch-then-lookup pattern, but its categorical band is fbfm13 and its parameter vocabulary includes fuel_load.live_foliage rather than FBFM40’s separate live herbaceous and woody loads. Seasonal layers are not available for FBFM13.

POST fbfm13/landfire
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/fbfm13/landfire' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Annual FBFM13 — LF2024",
"version": "2024"
}'

Poll the classification, save its id as your-fbfm13-grid-id, then run the FBFM13 lookup:

POST lookup/fbfm13
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/lookup/fbfm13' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "FBFM13 surface parameters",
"source_grid_id": "your-fbfm13-grid-id",
"source_band": "fbfm13",
"bands": [
"fuel_load.1hr",
"fuel_load.10hr",
"fuel_load.100hr",
"fuel_load.live_foliage",
"savr.1hr",
"fuel_depth"
]
}'

Record the result as your-fbfm13-lookup-grid-id.

FCCS uses fuelbed identifiers and exposes a different set of physical components — litter, duff, live shrub, and live herbaceous load rather than the timelag-based bands of the FBFM products. Like FBFM13, FCCS has no seasonal layers. remove_bare_ground controls whether bare-ground fuelbeds are removed during the fetch.

POST fccs/landfire
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/fccs/landfire' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "FCCS fuelbeds — LF2023",
"version": "2023",
"remove_bare_ground": false
}'

Poll the classification, save its id as your-fccs-grid-id, then use the FCCS lookup and its fccs source band:

POST lookup/fccs
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/lookup/fccs' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "FCCS surface parameters",
"source_grid_id": "your-fccs-grid-id",
"source_band": "fccs",
"bands": [
"fuel_load.litter",
"fuel_load.duff",
"duff_depth",
"fuel_load.live_shrub",
"fuel_load.live_herb",
"fuel_load.1hr"
]
}'

Record the result as your-fccs-lookup-grid-id.

Use the live API reference for the complete, current lookup-band enums. FBFM40, FBFM13, and FCCS accept different band names; do not reuse a band list across products without checking it.

LANDFIRE classifies fuels on a 30 m grid. When the output resolution is finer than 30 m — 2 m for QUIC-Fire, for instance — nearest-neighbor resampling copies each 30 m code into a block of identical cells, producing staircase edges between fuel model categories. boundary_scatter replaces those edges with ragged, natural-looking transitions by probabilistically mixing codes at category boundaries.

Side-by-side comparison of the same FBFM40 detail at 2 m resolution. The left panel shows staircase edges from nearest-neighbor resampling, with sharp rectangular boundaries between fuel model categories. The right panel shows the same area with boundary scatter enabled, where category transitions are ragged and natural-looking. The NB1 non-burnable boundary remains sharp in both panels.

A 320 × 320 m detail of FBFM40 at 2 m resolution. Without scatter (left), each 30 m source cell becomes a 15 × 15 block of identical codes, producing staircase edges. With scatter (right), codes are probabilistically mixed at category boundaries. The NB1 boundary stays sharp — non-burnable codes are protected from scattering.

Add boundary_scatter to any FBFM40, FBFM13, or FCCS create request. Pass {} for the defaults (depth 10, seed 42), or set them explicitly:

ParameterDefaultMeaning
depth10How many cells deep scattering can reach (1–50). Swap probability halves with each cell of distance, so most mixing happens in the first 3–4 cells.
seed42Random seed for reproducible results.
POST fbfm40/landfire with boundary_scatter
curl -X 'POST' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/fbfm40/landfire' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "FBFM40 — LF2024, 2 m scatter",
"version": "2024",
"alignment": {
"target": "domain",
"resolution": 2.0
},
"boundary_scatter": {}
}'

The response records boundary_scatter in source with the resolved defaults. Downstream lookups work identically — point the lookup at this classification the same way you would point it at a native-resolution one.

Each product has a coverage check that lists every version and season the API can serve for your domain, reports whether each one fully covers it, and identifies the latest release. Run it before choosing a version, especially for seasonal requests or domains near the edge of a LANDFIRE region.

GET fbfm40/landfire/coverage
curl -X 'GET' \
'https://api-v2-prod-782971006568.us-west1.run.app/domains/your-domain-id/grids/fbfm40/landfire/coverage' \
-H 'accept: application/json' \
-H 'api-key: my-api-key'

The releases array is sorted newest first. Each entry reports:

  • coverage: "full" — the version fully covers the domain and can be created. links.create contains the ready-made request: POST its body to its href (a path relative to the API base URL).
  • coverage: "partial" — the domain straddles a LANDFIRE region boundary. The create succeeds, but cells outside the served area are nodata.
  • coverage: "none" — LANDFIRE serves this release in other regions but not here. links.create is null.
  • coverage: "unpublished" — the season has not been published anywhere yet. year is null.

latest is the most recent release that fully covers the domain, whether annual or seasonal. In this example the domain is in the Southwest, where LANDFIRE has published seasonal fuels through summer 2026, so latest is LF2025 SU. A domain in a region where seasonal coverage has not rolled out would show an annual vintage as latest instead.

FBFM13 and FCCS have the same check at their own paths (/grids/fbfm13/landfire/coverage and /grids/fccs/landfire/coverage). Neither product has seasonal entries.

The lookup grid is the continuous surface-fuel product. The source classification remains useful for auditing which code produced each value.

  • Treating category codes as physical values. Run the lookup before using loads, depths, or SAVR in a model.
  • Using the wrong source band. Use fbfm for FBFM40, fbfm13 for FBFM13, and fccs for FCCS.
  • Running a lookup before the classification completes. Poll the fetch to completed; the lookup reads its stored cell values.
  • Assuming a season or vintage is available everywhere. Run the coverage check first. A domain with full annual coverage may still report none for a given season, and on-demand vintages roll out region by region.
  • Confusing vintage and represented year. source.version is the landscape vintage (the generation of LANDFIRE data); source.year is the calendar year the data represents. They match for annual products but diverge for seasonal layers, where the year is read from the LFPS catalog.
  • Comparing grids without checking georeferencing. Compare crs, transform, and shape; crop or resample to a common footprint when needed.
  • Treating resampling as added detail. Resampling a LANDFIRE grid to smaller cells changes its lattice, not the information content of the source product.
  • Applying boundary scatter at native resolution. Scatter has no effect when the output resolution matches the source (30 m). Set alignment.resolution to a finer grid before enabling it.