Most developers pull wind speed and direction from a weather API, render a little arrow on a map, and move on. Wind shear — the rate at which wind velocity changes with altitude or horizontal distance — gets skipped almost entirely, either because it’s not in the response or because it shows up as a number with no obvious interpretation. That’s a problem for the use cases where shear is actually the variable that matters: aviation briefings, paraglider launch windows, drone corridor planning, wind energy site assessment.
What follows is what shear data actually represents, where weather APIs get it from, and how to write code that does something useful with it rather than silently ignoring it.
Two kinds of shear, only one of which APIs usually give you
Vertical shear is the change in wind speed or direction between two altitude levels — the kind that rips apart convective storms and makes turbulence dangerous for aircraft on approach. Horizontal shear is variation across geographic space at the same altitude — relevant for offshore wind farm layout, for example. Most weather APIs, including ours, deal with vertical shear because that’s what’s derivable from NWP model output. GFS, NAM, HRRR, and ECMWF all report wind components at multiple pressure levels, which gives you the vertical profile; horizontal shear requires spatial differencing across grid cells, which most APIs don’t expose.
When an API returns a surface wind speed of 12 knots and a 500 hPa wind of 45 knots, the shear between those two points is implicit in the data — but you have to compute it yourself, or use an endpoint that’s already done it for you. Returning raw winds at multiple levels and expecting the client to diff them is honest, but it puts the calculation burden on you.
Where the numbers come from
Vertical wind shear in forecast APIs comes from NWP model pressure-level output. GFS reports wind components (u and v) at pressure levels from 1000 hPa up through 100 hPa and above. HRRR does the same at 3 km horizontal resolution, which matters in complex terrain — a valley and a ridge 10 km apart can have genuinely different shear profiles that GFS at ~13 km resolution will smooth over.
Our GRIB2 ingestion pipeline pulls this pressure-level wind data for GFS, NAM, HRRR, and ECMWF and resolves it to the locations we serve. The altitude-to-pressure conversion uses the hypsometric equation — temperature and pressure in, geometric altitude out. Not complicated, but it has to happen correctly before any shear calculation makes sense.
METAR observations don’t give you shear directly. A METAR will report surface winds, gusts, and sometimes a wind shear advisory in the WS remark field, but that advisory covers low-level wind shear near the runway environment specifically, not a general vertical profile. Worth distinguishing before you assume a METAR-based pipeline covers this.
What a shear value actually means in practice
Shear is typically expressed as a speed difference over a height interval — knots per 1,000 feet, or m/s per km. A surface-to-500m shear of 10 knots is very different from 30 knots, even if neither number sounds alarming on its own.
The NWS uses roughly these thresholds for low-level wind shear (surface to 2 km AGL) in convective contexts: below 20 knots is weak, 20–35 knots is moderate, above 35 knots is strong. But the meaningful layer depends entirely on your use case. For paragliding, even moderate shear in the lowest few hundred meters makes for an uncomfortable launch. For a utility-scale wind turbine, hub-height shear affects power curve performance and blade fatigue — IEC 61400-1 specifies a wind shear exponent (the power law coefficient, typically 0.2 for open terrain) that turbine manufacturers use to model load cycles. For drone operations under FAA Part 107, the relevant layer is surface to 120 m AGL. For pilots on approach, you care about surface to 1,500 feet AGL, and separately about mid-level shear that drives en route turbulence.
The thresholds aren’t universal. Apply the one that fits the altitude band your use case actually operates in.
A concrete example: computing shear from multi-level wind data
Say you’ve fetched forecast data and you have wind speed at 10 m AGL and at 850 hPa. You need the height of 850 hPa to compute shear. A quick hypsometric approximation:
# Approximate height of 850 hPa given surface pressure ~1013 hPa
import math
def pressure_to_altitude_m(p_hpa, p0_hpa=1013.25):
# Barometric formula approximation — sufficient for a shear calc
return -8500 * math.log(p_hpa / p0_hpa)
alt_850 = pressure_to_altitude_m(850) # ~1457m
alt_10m = 0.01 # surface wind reported at 10m AGL
wind_surface_ms = 6.0 # m/s at 10m
wind_850_ms = 18.0 # m/s at 850 hPa
shear_per_km = (wind_850_ms - wind_surface_ms) / ((alt_850 - alt_10m) / 1000)
print(f"Shear: {shear_per_km:.1f} m/s per km")
# Shear: 8.2 m/s per km
That’s a derivable shear index from pressure-level wind data that any reasonably complete weather API provides. You don’t need a dedicated shear endpoint — you need the multi-level wind fields and a few lines of arithmetic.
For direction shear, compute the vector difference instead of the scalar one. Veering winds with height (clockwise rotation in the Northern Hemisphere) indicate warm air advection; backing indicates cold air advection. That distinction matters for storm forecasting but is overkill for most app contexts.
The honest limitation
NWP pressure-level output is smoothed. HRRR at 3 km is better than GFS at 13 km for localized shear near terrain features, but it’s still not a radiosonde. Real atmospheric wind profiles have sharp kinks — nocturnal low-level jets are a common example — that models represent as a smooth ramp. If your use case requires precise shear at a specific altitude for safety-critical decisions (actual aviation dispatch, not a hobby app), API data should inform a proper briefing, not replace one. That means cross-referencing PIREPs and sounding data from the nearest upper-air station.
We’d rather say that plainly than let someone over-trust an API response in a context where it’s not the right data source.
What this looks like as a UI decision
You probably don’t want to surface a raw shear number to end users. What works better is a derived signal: a traffic-light rating, an advisory string, a flag on a time-series chart. If computed low-level shear exceeds 15 m/s per km, flag the launch window as high shear — check conditions on-site. The number lives in your backend logic; the user sees an actionable interpretation.
The same pattern fits an outdoor advisory endpoint — aggregating shear, visibility, precipitation probability, and temperature into a composite score per time window, with a reason string attached. The math stays server-side; the consumer gets a rating they can act on rather than six numbers they have to interpret themselves.
If you’re already pulling multi-level wind data from any forecast API, spend ten minutes computing shear before deciding the data isn’t useful. It’s almost certainly there — it’s just not labeled.
