Sentinel-2 Indices: The Big Cheat Sheet (Formulas, Uses, and Pitfalls)

Before you copy-paste

Here are the four details that decide whether your “same formula” is comparable across dates and tools.

Processing level: Prefer L2A (BOA surface reflectance) for cross-date analytics; reach for L1C (TOA reflectance) when atmospheric correction is likely to be unstable for your season and latitude.- Scale: Sentinel-2 reflectance is distributed as quantized integers in many SAFE-derived deliveries; the reflectance quantification value is commonly 10000, meaning reflectance is DN divided by 10000 when no offset is present.- NIR choice: B8 is wide NIR at 10 m; B8A is narrow NIR at 20 m. Use B8 for most 10 m vegetation work and keep B8A for red-edge focused work or cross-sensor comparisons where NIR center wavelength matters.

Masks: Indices are sensitive to cloud, shadow, haze, and snow. A slightly worse-looking map with conservative masking beats a smooth-looking map that leaks clouds into your time series.

The index cheat sheet

This table is intentionally “one screen of truth”: one row per index, with the formula written in Sentinel-2 band names and the main reason people reach for it. If you are training models, treat the “Why/When” column as feature intent and validate thresholds per crop, season, and region.

Category | Index | Formula (Sentinel-2) | Why/When | Common pitfall
Vegetation | NDVI | (B8 - B4) / (B8 + B4) | The default greenness signal at 10 m. | Saturates in dense canopy; can drift with haze if masking is weak.
Vegetation | EVI2 | 2.5 * (B8 - B4) / (B8 + 2.4*B4 + 1) | NDVI alternative that stays responsive in denser canopy and bright soils, without Blue. | Needs 0 to 1 reflectance because of the constant + 1.
Vegetation | NDRE (B5) | (B8A - B5) / (B8A + B5) | Chlorophyll and stress sensitivity later into the season than NDVI. | Mixing B8A and B8 across dates introduces small but real offsets.
Vegetation | NDRE (B6) | (B8A - B6) / (B8A + B6) | Red-edge variant that probes a bit deeper into canopy structure. | Requires consistent resampling if you work at 10 m.
Vegetation | NDRE (B7) | (B8A - B7) / (B8A + B7) | Red-edge variant for dense canopy discrimination. | Red-edge indices are fragile under residual cloud haze.
Vegetation | NIRv | B8 * ((B8 - B4) / (B8 + B4)) | A vegetation signal often used as a productivity proxy feature. | Unit scale matters; compute on reflectance, not raw DN.
Vegetation | OSAVI | 1.16 * (B8 - B4) / (B8 + B4 + 0.16) | Soil-adjusted vigor when canopy is sparse or soils are bright. | Needs 0 to 1 reflectance because of the constants.
Vegetation | VARI | (B3 - B4) / (B3 + B4 - B2) | Visible-only greenness when NIR is unreliable or missing. | Much more sensitive to haze and illumination changes than NIR-based indices.
Moisture | NDMI | (B8 - B11) / (B8 + B11) | Vegetation water content proxy using NIR and SWIR1. | If you do not mask clouds, SWIR can produce convincing false “dryness”.
Moisture | MSI | B11 / B8 | Simple moisture stress ratio (higher often means drier). | Ratio is sensitive to small denominators in shadow and water edges.
Moisture | NDWI (McFeeters) | (B3 - B8) / (B3 + B8) | Water and moisture contrast using Green and NIR. | Vegetation and built-up areas can overlap with water in mixed pixels.
Moisture | NDWI (Gao style) | (B8 - B11) / (B8 + B11) | Moisture-style NDWI variant that is algebraically identical to NDMI on Sentinel-2. | Naming confusion causes teams to mix “NDWI” definitions without noticing.
Burn | NBR | (B8 - B12) / (B8 + B12) | Burn severity and char sensitivity using NIR and SWIR2. | Works best with pre and post dates that match season and phenology.
Burn | NBR2 | (B11 - B12) / (B11 + B12) | Burn and recovery context using SWIR1 and SWIR2. | Very sensitive to residual clouds and wet soil after rain.
Burn | dNBR | NBR_pre - NBR_post | Simple change metric for severity mapping between two dates. | “Pre” and “post” must be comparable in season and solar geometry.
Burn | BAI | 1 / ((0.1 - B4)^2 + (0.06 - B8)^2) | Burn scar highlight in some landscapes. | Noise-sensitive; do not treat as stable across sensors or processing chains.
Water | MNDWI | (B3 - B11) / (B3 + B11) | Water extraction that suppresses built-up areas better by using SWIR instead of NIR. | Can over-pick wet soil or dark roofs in shadow without a shadow mask.
Water | AWEI_sh | B2 + 2.5B3 - 1.5(B11 + B12) - 0.25*B8 | Water index designed to be more robust under shadow. | Needs reflectance scaling because of the constants and coefficients.
Water | AWEI_nsh | 4*(B3 - B11) - (0.25B8 + 2.75B12) | Water index variant for non-shadowed conditions. | Misbehaves if your SWIR is noisy or poorly masked for haze.
Water | WI2015 | 1.7204 + 171*(B2 + B3 + B4) - 3*(B2B3) - 1.8(B2B4) - 48(B3B4) - 0.8(B8*B11) | Empirical separation in complex scenes (often urban and shadow). | Extremely sensitive to scaling and preprocessing; do not use on raw DN.
Water | Green/Blue ratio | B3 / B2 | Quick qualitative turbidity proxy in clear-sky conditions. | Illumination and atmosphere can dominate; treat as relative, not absolute.
Snow | NDSI | (B3 - B11) / (B3 + B11) | Snow detection using Green and SWIR1. | Cloud and snow confusion is common without a conservative mask.
Snow | Snow brightness | (B3 + B2) / 2 | Simple brightness cue that supports snow screening. | Bright sand and cloud edges can look like snow.
Urban/Soil | NDBI | (B11 - B8) / (B11 + B8) | Built-up vs vegetation contrast using SWIR1 and NIR. | Fails in bare soil and dry residue unless you add context features.
Urban/Soil | IBI | (NDBI - NDVI) / (NDBI + NDVI) | Built-up emphasis that dampens vegetation influence. | Not stable if NDVI is noisy due to weak masking.
Urban/Soil | SAVI | 1.5 * (B8 - B4) / (B8 + B4 + 0.5) | Vegetation with soil adjustment (often L = 0.5). | Needs 0 to 1 reflectance because of the constant.
Urban/Soil | BSI | ((B11 + B4) - (B8 + B2)) / ((B11 + B4) + (B8 + B2)) | Highlights bright bare soil; separates from veg and water. | Cloud shadow can flip sign and create false “soil” patches.

Pitfalls and gotchas that break time series

Most failures are not “wrong formula”. They are input semantics drift.

First, compute indices on reflectance. If you ingest SAFE-style integers yourself, apply the scale (and any band-dependent offsets) before computing anything with constants, multiplications, or additive terms. A good mental model is: normalized differences are forgiving of a shared multiplicative scale, but they are not forgiving of additive offsets, and they are not forgiving of constants.

Second, understand the post-2022 offset story so you do not silently “double fix” data. ESA introduced a band-dependent radiometric offset in Processing Baseline 04.00 (January 2022) to preserve information over dark surfaces, and several platforms label their collections “harmonized” when that offset has already been removed for you.If you start from a harmonized feed, do not apply the offset correction again.

Third, B8 versus B8A is not a cosmetic choice. They differ in center wavelength, bandwidth, and native resolution, so mixing them can move your baselines just enough to break thresholds in early warning workflows. If you need 10 m analytics but depend on red-edge and SWIR bands, resample once to a fixed grid and keep the resampler consistent.

Finally, treat masking as part of the method, not an afterthought. Most index “weirdness” in Sentinel-2 is cloud and shadow contamination that looks plausible because the index math is simple.

ClearSKY in practice

ClearSKY can deliver Sentinel-2 style band stacks as Level-1 (TOA) or Level-2 (BOA) reflectance, with cloud-clearing and cross-date consistency handled by AI data fusion where appropriate. Depending on the model and product mode, you can receive 10, 12, or full 13-band style outputs aligned on a single analysis grid, so index computation and parcel statistics do not require per-band reprojection or manual co-registration. If you request indices alongside bands, keep the source band list explicit and keep processing versions pinned within a season so changes reflect fields and conditions, not pipeline drift.

FAQ

Do I need L2A (BOA) for indices, or is L1C (TOA) fine?

L2A is the safer default for cross-date analytics because it targets surface reflectance and reduces atmospheric variability. L1C can be useful when you need the lowest latency or when atmospheric correction is likely to be unstable for your region and season. The important rule is consistency: pick one level for a series, then validate early and stick to it.

Do I always need to divide Sentinel-2 values by 10,000?

Many Sentinel-2 deliveries store reflectance as quantized integers with a typical quantification value of 10000, so DN divided by 10000 yields reflectance in the 0 to 1 range. Some APIs and platforms already return floats, in which case you should not rescale again. If an index includes constants or multiplications, treat reflectance scaling as mandatory rather than optional.

Should I use B8 or B8A in my vegetation indices?

Use B8 for most parcel-scale vegetation work because it is 10 m and is the standard choice for NDVI and EVI2 on Sentinel-2. Use B8A when you are pairing with red-edge bands or validating cross-sensor thresholds where the NIR center wavelength matters. Avoid mixing B8 and B8A inside a single time series unless you quantify the shift and re-tune thresholds.

NDMI vs NDWI: Why do I see the same formula with different names?

Some names overlap across papers and communities, and on Sentinel-2 the “moisture-style NDWI” is often algebraically identical to NDMI because both use NIR and SWIR1. The safest practice is to document the exact formula alongside the name in your code and reports. If two teams both say “NDWI” but mean different band pairs, you will get a silent mismatch.

What is the fastest way to keep indices comparable across dates?

Lock three things early: processing level, masking policy, and grid alignment. Reproject or resample once to a fixed grid and keep the resampler consistent, especially when you mix 10 m and 20 m bands. Then track per-parcel summary statistics instead of chasing single-pixel noise.

Why do my index maps have seams, holes, or extreme spikes?

Seams often come from inconsistent resampling or reprojection across dates, especially when 20 m and 10 m bands are mixed without a fixed grid. Holes are usually masking or missing data behavior, while spikes are often division instability in shadows or at water edges. Check scaling, check masks, and clamp denominators in code so small values do not explode.