intermediate 6 min read

INDEX MATCH with ARRAYFORMULA in Google Sheets

ARRAYFORMULA doesn't spill INDEX MATCH down a column, INDEX only returns the first match. Here's why, and the MAP + LAMBDA formula that returns a result for every row from one cell.

SB

Sheets Bootcamp

March 3, 2026 ยท Updated May 12, 2026

INDEX MATCH normally looks up one value at a time. It is tempting to wrap it in ARRAYFORMULA to fill a whole column from one cell, but that does not work, because INDEX only ever returns the first match. This guide shows exactly why the ARRAYFORMULA approach fails, gives you the MAP + LAMBDA formula that actually returns a result for every row, and covers blank rows, open-ended ranges, and common errors.

In This Guide

Why One Formula for a Whole Column?

When you have a column of lookup values (like a list of Product IDs), the standard approach is to write an INDEX MATCH formula in the first row and copy it down. This works, but it creates a separate formula in every cell.

Problems with copying formulas down:

  • Hundreds of individual formulas slow down recalculation
  • New rows require manually copying the formula to each one
  • Editing the formula means updating every cell, not just one

The goal is one formula, in one cell, that fills every row automatically. The catch is that the obvious tool for this, ARRAYFORMULA, does not work with INDEX MATCH. The next section explains why, and what to use instead.

The Formula Pattern

The natural instinct is to swap the single cell H2 for the range H2:H5 and wrap the whole thing in ARRAYFORMULA:

Formula
=ARRAYFORMULA(INDEX(D2:D9, MATCH(H2:H5, A2:A9, 0)))

This does not return four different prices. It returns the first price, repeated four times (for example $35.00 in all four rows). MATCH correctly produces an array of four positions, but INDEX is not array-aware over its position argument, it reads only the first position and ignores the rest. ARRAYFORMULA cannot fix this, because the limitation lives inside INDEX itself.

The working pattern uses MAP with LAMBDA to run a separate INDEX MATCH for each value in the search column:

Formula
=MAP(search_column, LAMBDA(id, IF(id="", "", INDEX(return_range, MATCH(id, lookup_range, 0)))))

MAP walks down every value in search_column, and the LAMBDA runs a fresh INDEX(..., MATCH(id, ...)) for that single value. Because each row gets its own INDEX call, each row gets its own correct result. The IF(id="", "", ...) check handles blank rows so they return an empty string instead of an error.

Note

If you specifically want an array-aware one-cell wrapper, use ARRAYFORMULA with VLOOKUP instead of INDEX MATCH, VLOOKUP does accept an array of search keys and spills correctly. See VLOOKUP with ARRAYFORMULA. MAP + LAMBDA is the equivalent that keeps the INDEX MATCH structure (and works for left lookups, which VLOOKUP cannot do).

Step-by-Step Setup

Weโ€™ll look up prices from the product inventory for a list of Product IDs.

Sample Data

The product inventory has Product IDs in column A and Prices in column D (8 products, rows 2 through 9). A separate list of Product IDs sits in column H (4 IDs in H2:H5).

Product inventory with lookup IDs in column H

1

Set up your lookup table and search column

The inventory table runs from A1:F9. The lookup list in H2:H5 contains four Product IDs: SKU-103, SKU-106, SKU-101, and SKU-108. You want to return the price for each one in column I.

2

Write a single-row INDEX MATCH

Start with a standard INDEX MATCH formula in I2:

Formula
=INDEX(D2:D9, MATCH(H2, A2:A9, 0))

This returns $35.00, the price for SKU-103. But it only works for one row. Copying it down to I3, I4, and I5 works, but leaves you with four separate formulas to maintain.

3

Spill the lookup down the column with MAP

You might expect to replace H2 with the range H2:H5 and wrap it in ARRAYFORMULA. That returns $35.00 four times, not four different prices, INDEX only reads the first match. Use MAP with LAMBDA instead:

Formula
=MAP(H2:H5, LAMBDA(id, IF(id="", "", INDEX(D2:D9, MATCH(id, A2:A9, 0)))))

Enter this formula in I2 only. MAP runs the INDEX MATCH once per Product ID, returning all four prices at once:

H (Product ID)I (Price)
SKU-103$35.00
SKU-106$19.99
SKU-101$24.99
SKU-108$89.99

MAP with INDEX MATCH returning prices for four Product IDs at once

One formula, four results. Cells I3:I5 show results but contain no formula of their own, they are filled by the MAP in I2.

Important

The cells below the MAP cell (I3, I4, I5) must be empty. If any of them contain data or formulas, the formula returns a #REF! error because a spilled array cannot overwrite existing content.

Handle Blank Rows

Without a blank check, an empty cell in the search column makes MATCH look for an empty string, which produces a #N/A error for that row.

The IF(id="", "", ...) check inside the LAMBDA suppresses this:

Formula
=MAP(H2:H5, LAMBDA(id, IF(id="", "", INDEX(D2:D9, MATCH(id, A2:A9, 0)))))

When H3 is empty, the formula returns an empty string for that row instead of an error. All other rows still return their lookup results.

Tip

For extra safety, add IFERROR to handle lookup values that do not exist in the inventory: =MAP(H2:H5, LAMBDA(id, IF(id="", "", IFERROR(INDEX(D2:D9, MATCH(id, A2:A9, 0)), "Not found")))).

Open-Ended Ranges for Growing Data

If new Product IDs get added to column H regularly, pass an open-ended range to MAP:

Formula
=MAP(H2:H, LAMBDA(id, IF(id="", "", IFERROR(INDEX(D2:D9, MATCH(id, A2:A9, 0)), "Not found"))))

H2:H (no end row) means โ€œH2 to the bottom of the sheet.โ€ New IDs added in H6, H7, or beyond are included automatically. The IF(id="", "", ...) check is essential here, an open-ended range includes thousands of empty rows, and without it every one would return an error.

MAP with an open-ended range handling new rows automatically

Note

Open-ended ranges scan the entire column, which can be slow on very large sheets. If performance is a concern and you know the maximum row count, use a bounded range like H2:H500 instead of H2:H.

Common Errors

Same result repeated in every row

If every row shows the same value, for example $35.00 four times instead of four different prices, you are almost certainly using ARRAYFORMULA(INDEX(..., MATCH(H2:H5, ...))). INDEX ignores the array of positions from MATCH and returns only the first one, and ARRAYFORMULA cannot change that.

Fix: Switch to MAP + LAMBDA so each row runs its own INDEX MATCH: =MAP(H2:H5, LAMBDA(id, INDEX(D2:D9, MATCH(id, A2:A9, 0)))).

#REF!: Cells below are not empty

A spilled array needs empty cells below the formula cell to fill. If I3 contains a value or formula, the MAP in I2 returns #REF!.

Fix: Clear all cells in the output column below the formula cell.

#N/A: Lookup value not found

A Product ID in column H does not exist in the inventory. MATCH cannot find it and returns #N/A.

Fix: Wrap the lookup in IFERROR: IFERROR(INDEX(D2:D9, MATCH(id, A2:A9, 0)), "Not found").

Slow performance

MAP over an open-ended range on large sheets (10,000+ rows) can be slow because it evaluates the LAMBDA for every row.

Fix: Use a bounded range (H2:H500) instead of H2:H. For very large datasets, an array-aware ARRAYFORMULA(VLOOKUP(H2:H, ...)) is often faster than MAP, see VLOOKUP with ARRAYFORMULA.

Tips

  1. Reach for MAP, not ARRAYFORMULA, with INDEX MATCH. ARRAYFORMULA does not spill INDEX MATCH down a column, INDEX returns only the first match. MAP runs a fresh lookup per row and actually works.

  2. Always include the blank check. IF(id="", "", ...) inside the LAMBDA prevents #N/A errors on empty rows. This is essential when using open-ended ranges like H2:H.

  3. Use IFERROR for missing values. Not every lookup value may exist in the source data. IFERROR handles this gracefully without breaking the spill.

  4. Need a true array-aware wrapper? Use VLOOKUP. Unlike INDEX MATCH, VLOOKUP accepts an array of search keys, so ARRAYFORMULA(VLOOKUP(H2:H5, ...)) spills correctly. Use MAP + LAMBDA when you need INDEX MATCH specifically, for example, left lookups where the return column is to the left of the lookup column. See VLOOKUP with ARRAYFORMULA.

  5. For returning multiple matching rows, use FILTER. MAP with INDEX MATCH returns one result per search key. If a single search key has multiple matches, see INDEX MATCH to return multiple results.

Frequently Asked Questions

Can I use INDEX MATCH with ARRAYFORMULA?
Not the way most people expect. Wrapping INDEX MATCH in ARRAYFORMULA and passing a column range does not return a different result per row, because INDEX is not array-aware over its position argument, it uses only the first match from MATCH and repeats it. To spill INDEX MATCH down a whole column from one cell, use MAP + LAMBDA: =MAP(search_column, LAMBDA(id, INDEX(return_range, MATCH(id, lookup_range, 0)))). If you want a genuine array-aware wrapper, use ARRAYFORMULA with VLOOKUP instead, since VLOOKUP does accept an array of search keys.
Why does my ARRAYFORMULA INDEX MATCH return only one result?
Because INDEX ignores the array of positions that MATCH returns and uses only the first one, so every row shows the same value (for example the first price repeated four times). ARRAYFORMULA cannot fix this, the limitation is inside INDEX. Switch to =MAP(search_column, LAMBDA(id, INDEX(return_range, MATCH(id, lookup_range, 0)))), which runs a fresh INDEX MATCH for each row.
Is MAP with INDEX MATCH faster than copying formulas down?
A single MAP formula is generally faster and cleaner than hundreds of individual formulas because Google Sheets processes it as one calculation and there is only one formula to maintain. On very large ranges MAP can be slower than a single array-aware VLOOKUP, so for big datasets compare it against ARRAYFORMULA(VLOOKUP(...)).
What happens when new rows are added?
If your MAP references an open-ended range like H2:H (no end row), new Product IDs added below are included automatically. Use open-ended ranges for data that grows over time, or a bounded range like H2:H500 if performance matters.
Can I use MAP or ARRAYFORMULA with INDEX MATCH MATCH?
For a two-way lookup that spills down a column, wrap INDEX MATCH MATCH in MAP so each row runs its own row-and-column match: =MAP(search_column, LAMBDA(id, INDEX(data, MATCH(id, row_keys, 0), MATCH(col_label, col_keys, 0)))). Plain ARRAYFORMULA will not do this because INDEX is not array-aware over either position argument.

You've googled this formula before. Probably more than once.

Basic Training is a free course inside a real Google Sheet that grades every formula the moment you press Enter. 7 lessons, about 40 minutes, and this loop ends.

Try the Sheet That Grades You

Free. No spam, ever.

Get Free Basic Training