# How to Handle Different GRIB2 Product Types in Herbie: Surface, Pressure, and Native Grids

> Learn to handle GRIB2 product types like surface, pressure, and native grids with Herbie. Select products, filter inventory, and download specific variables easily.

- Repository: [Brian Blaylock/herbie](https://github.com/blaylockbk/herbie)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Use Herbie's model templates to select GRIB2 product types via the `product` parameter, then filter inventory and download subsets using the `search` parameter to isolate specific variables like surface pressure or native-level fields.**

Herbie is an open-source Python library that simplifies downloading and reading numerical weather prediction (NWP) model output from various sources. When working with GRIB2 files—particularly from high-resolution models like HRRR, GFS, or RRFS—you must specify the **product type** (surface, pressure-level, or native-level) to access the correct vertical coordinate system and variables.

## Understanding GRIB2 Product Types in Herbie

### The Template-Based Architecture

Every NWP model in Herbie is defined by a **template module** that specifies available product types through a `PRODUCTS` dictionary mapping keys to descriptions, and a `SOURCES` dictionary defining URL patterns. 

In [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py), the `Herbie` class validates your selection against these definitions during initialization. The `_validate` method checks that `self.product in self.PRODUCTS` (lines 184-190), ensuring you request a supported configuration before attempting downloads.

### Key Product Categories

- **Surface (`sfc`)**: Variables at ground level (2-meter temperature, surface pressure)
- **Pressure levels (`prs` or `pgrb2`)**: Data interpolated to standard pressure surfaces (500 hPa, 850 hPa)
- **Native levels (`nat` or `natlev`)**: Model's original vertical coordinate system (eta or hybrid levels)

## Selecting Product Types for Different Models

### HRRR Native-Level Fields

The HRRR model template in [`src/herbie/models/hrrr.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/hrrr.py) defines the native-level product as `"nat"` (lines 77-82), representing 3-km resolution fields on the model's native vertical coordinate. Access these by setting `product="nat"`:

```python
from herbie import Herbie

H = Herbie(
    date="2023-09-15 12:00",
    model="hrrr",
    product="nat",
    fxx=0
)

```

### GFS Pressure-Level Products

For global models like GFS, pressure-level data typically uses product keys like `pgrb2.0p25` as defined in [`src/herbie/models/gfs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/gfs.py) (lines 42-49). This provides standard pressure-level variables at 0.25-degree resolution:

```python
G = Herbie(
    date="2023-09-15 00:00",
    model="gfs",
    product="pgrb2.0p25",
    fxx=6
)

```

### RRFS Native Level Transformations

The RRFS template in [`src/herbie/models/rrfs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/rrfs.py) demonstrates product key transformations, converting `"nat"` to `"natlev"` internally (lines 38-42) to match the specific file naming conventions of the Rapid Refresh Forecast System.

## Filtering Inventory by Product Type

Once you've selected a product, use the `inventory()` method to inspect available variables. The method parses `.idx` files using `wgrib2` (via [`src/herbie/wgrib2.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/wgrib2.py), lines 46-55) and returns a searchable pandas DataFrame.

To isolate specific fields like surface pressure from native grids:

```python

# Search for surface pressure in native-level data

df = H.inventory(search=":SLP:")
print(df[["variable", "level", "valid_time"]])

```

The `search` parameter applies regex filtering to the `search_this` column (lines 276-285 in [`core.py`](https://github.com/blaylockbk/herbie/blob/main/core.py)), allowing you to distinguish between surface fields and upper-air variables within the same product file.

## Downloading and Converting Specific Product Data

### Subsetting by Byte Ranges

Herbie enables efficient partial downloads by reading the inventory index and retrieving only the byte ranges matching your search criteria. The `download()` method (lines 334-382 in [`core.py`](https://github.com/blaylockbk/herbie/blob/main/core.py)) accepts a `search` parameter to fetch specific variables without downloading the entire GRIB2 file:

```python

# Download only surface pressure messages

slp_file = H.download(search=":SLP:")

```

### Loading into xarray

Convert any product type to an `xarray.Dataset` using the `xarray()` method (lines 1249-1285 in [`core.py`](https://github.com/blaylockbk/herbie/blob/main/core.py)), which uses `cfgrib` as the backend engine. Native-level coordinates are preserved automatically:

```python
ds = H.xarray(search=":SLP:")
ds.SLP.sel(valid_time=ds.valid_time[0]).plot()

```

This workflow applies uniformly across all product types—whether accessing surface grids, pressure levels, or native coordinates—because the template architecture abstracts model-specific file structures.

## Summary

- Herbie uses **model templates** to define valid GRIB2 product types via the `PRODUCTS` dictionary in each model module.
- Set the `product` parameter when instantiating `Herbie` to select surface (`sfc`), pressure-level (`prs`), or native-level (`nat`) grids.
- The `_validate` method in [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py) ensures your selected product exists for the chosen model and date.
- Use `inventory(search="...")` to filter variables within a product type before downloading.
- Download subsets efficiently by specifying search criteria, then load into **xarray** with `cfgrib` to preserve native vertical coordinates.

## Frequently Asked Questions

### What is the difference between native-level and pressure-level GRIB2 products?

Native-level products (`nat` or `natlev`) contain data on the model's original vertical coordinate system (such as eta or hybrid sigma-pressure levels), preserving the full vertical resolution of the forecast system. Pressure-level products (`prs` or `pgrb2`) interpolate these fields to standard pressure surfaces (e.g., 850 hPa, 500 hPa) for easier comparison across different models and observations. According to the Herbie source code, you access these by specifying different `product` keys in the model template.

### How do I find which product types are available for a specific model?

Each model template in `src/herbie/models/` defines a `PRODUCTS` dictionary mapping available keys to descriptions. For example, [`src/herbie/models/hrrr.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/hrrr.py) lists `"nat"` for native levels, `"sfc"` for surface, and `"prs"` for pressure levels. You can inspect this dictionary programmatically by importing the template module or checking the model documentation in the repository.

### Can I download variables from multiple product types simultaneously?

No, Herbie instances are bound to a single product type per initialization. To access variables from different vertical coordinates (e.g., surface pressure from `sfc` and geopotential height from `prs`), create separate `Herbie` objects with different `product` parameters, then merge the resulting xarray Datasets manually using `xarray.merge()` or concatenation methods.

### Why does the RRFS model use "natlev" instead of "nat" for native levels?

The RRFS template in [`src/herbie/models/rrfs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/rrfs.py) performs an internal transformation (lines 38-42) that maps the user-facing `"nat"` key to the backend file identifier `"natlev"`. This accommodates the specific file naming conventions used by the Rapid Refresh Forecast System while maintaining a consistent interface across Herbie's supported models.