OFFSET Generator
Return a reference shifted a set number of rows and columns from a starting cell, optionally resized.
OFFSET
Return a reference shifted a set number of rows and columns from a starting cell, optionally resized.
The anchor cell or range the offset is measured from.
Positive moves down, negative moves up, 0 stays on the same row.
Positive moves right, negative moves left, 0 stays in the same column.
How many rows tall the returned reference should be. 1 returns a single row. Optional in Excel and Sheets - delete it and the width from the copied formula to inherit the anchor's own size.
How many columns wide the returned reference should be. 1 returns a single column.
=OFFSET($A$1, 2, 3, 1, 1)Worked Example
You want to read the cell three columns right and two rows down from the top-left of your data.
=OFFSET($A$1, 2, 3, 1, 1)Returns: Returns the value in D3: two rows down and three columns right of A1, sized to a single cell.
Checks Before You Paste
- •OFFSET is volatile: it recalculates on every change anywhere in the workbook. A rolling-window model built from hundreds of OFFSET calls is the usual reason a file takes seconds to respond to a keystroke.
- •A height or width above 1 makes OFFSET return a multi-cell range. That is fine inside SUM, AVERAGE, or COUNT - =SUM(OFFSET($A$1, 0, 0, 12, 1)) - and it spills in Microsoft 365 and Excel 2021. In older Excel, entered on its own it falls back to implicit intersection, returning the single value on the formula's own row or #VALUE! when the range does not line up with it.
- •The offset is measured from the top-left cell of the reference, and any move that lands outside the worksheet gives #REF! - so negative rows from row 1, or negative cols from column A, will break the formula.
How OFFSET works
Availability: Every version of Excel, Excel for the web, Google Sheets and LibreOffice Calc. The spilling behaviour described below applies to Excel 2021 and Microsoft 365; in earlier versions a multi-cell OFFSET result has to be consumed by another function or array-entered.
OFFSET builds a reference by walking away from a starting point. Give it an anchor cell, a number of rows to move down, a number of columns to move right, and optionally a height and width, and it returns the reference it lands on. It does not return a value as such - it returns a range, which Excel then evaluates. That distinction is the whole function: OFFSET is at its most useful wrapped in SUM, AVERAGE or COUNT, where the range it produces can be many cells tall.
The classic job is a range that resizes itself. =SUM(OFFSET($B$2, COUNT($B$2:$B$1000)-12, 0, 12, 1)) totals the last twelve numbers in column B and keeps doing so as rows are added, and the same construction defines the dynamic named ranges that older charts use to grow with their data. Negative values move the other way: negative rows move up, negative columns move left, and 0 in either slot means stay put.
Two things make OFFSET expensive. It is volatile, so it recalculates on every change anywhere in the workbook and forces everything that depends on it to recalculate too - a model with hundreds of them is the usual reason a file lags a keystroke behind. And because the reference is computed rather than written, Excel's auditing tools cannot follow it, so nothing warns you when the anchor is moved or the shape stops making sense.
Most of what OFFSET was used for now has a better answer. An Excel Table expands automatically, so a chart or a formula pointing at a Table column needs no dynamic range at all. INDEX also returns a reference, can be used at either end of a range with the colon operator - $B$2:INDEX($B$2:$B$1000, COUNT($B$2:$B$1000)) - and is not volatile. In Microsoft 365, TAKE and DROP express "the last twelve rows" directly. OFFSET is still the right tool when the shift genuinely has to be calculated in both directions at once, and it remains in enough existing workbooks to be worth reading fluently.
Syntax
=OFFSET(reference, rows, cols, [height], [width])| Argument | Required | What it does |
|---|---|---|
reference | Required | The anchor the move is measured from. A cell or a range; when it is a range, the offset is measured from its top-left cell and the omitted height and width default to that range's own size. |
rows | Required | How many rows to move. Positive moves down, negative moves up, 0 stays on the same row. Decimals are truncated toward zero. |
cols | Required | How many columns to move. Positive moves right, negative moves left, 0 stays in the same column. |
height | Optional | How many rows tall the returned reference should be, counting the landing cell as the first. Must be 1 or more; omitted, it inherits the height of reference. |
width | Optional | How many columns wide the returned reference should be. Must be 1 or more; omitted, it inherits the width of reference. |
More worked examples
Monthly figures are added to column B from B2 downwards, and a KPI cell has to show the total of the most recent twelve months.
=SUM(OFFSET($B$2, COUNT($B$2:$B$1000)-12, 0, 12, 1))Returns: With 30 months entered, COUNT returns 30, the reference starts 18 rows below B2 at B20, and the formula sums B20:B31 - the last twelve values.
It returns #REF! until there are at least twelve values, because the start row would be above B2. Guard it with IF(COUNT(...)<12, ...).
A defined name used as a chart series that should grow as new rows are typed underneath.
=OFFSET($A$2, 0, 0, COUNTA($A$2:$A$1000), 1)Returns: Returns A2:A45 when 44 labels have been entered, and A2:A46 the moment a forty-fifth is added.
COUNTA counts filled cells, not the distance to the last one, so a blank in the middle of the column makes this range stop short.
Reading the most recently entered value in a gap-free column A.
=OFFSET($A$1, COUNTA($A:$A)-1, 0)Returns: With 120 filled cells from A1 down, returns the contents of A120.
=LOOKUP(2, 1/($A:$A<>""), $A:$A) does the same job without volatility and copes with gaps.
Common mistakes
- #REF! from moving off the sheet
- Any offset that lands outside the worksheet fails: negative rows from row 1, negative cols from column A, or a height that would run past the last row. The commonest version is a rolling-window formula run before enough data exists, where COUNT minus the window size goes negative.
- Height or width below 1
- Both must be at least 1. A height driven by COUNTA returns #REF! on an empty column, since the count is 0. Wrap the argument in MAX(1, ...) so the range collapses to one row instead of erroring.
- Volatility multiplied by dependants
- OFFSET recalculates on every edit, and so does everything downstream of it. Thirty dynamic named ranges feeding thirty chart series will recalculate on every keystroke in the workbook. Replace them with Table columns, which expand on their own and cost nothing.
- COUNTA-based ranges cut short by gaps
- COUNTA counts non-empty cells, so one blank row halfway down makes the dynamic range end one row early and quietly drops the last value. Use a Table, or count to the last used row with =MATCH(1E+306, $A:$A) for numbers or =MATCH("zzzz", $A:$A) for text.
- Using a multi-cell result on its own
- =OFFSET($A$1, 0, 0, 12, 1) typed into a single cell spills down twelve cells in Excel 2021 and Microsoft 365, and returns #VALUE! or a single value by implicit intersection in older versions. If you want one number, wrap it in SUM or AVERAGE and be explicit about which.
Frequently Asked Questions
=OFFSET($A$2, 0, 0, COUNTA($A$2:$A$1000), 1) is the traditional answer, defined as a name and used wherever the range is needed. In any file you can change, converting the data to an Excel Table is better: Table columns resize themselves, are not volatile, and read as Sales[Amount] rather than as an offset calculation.
A range the same size and shape as the anchor. With a single-cell anchor that means one cell; with an anchor of A1:C3 it means a three-by-three block starting at the landing cell. Supplying the arguments explicitly is clearer, since the inherited size is invisible to whoever reads the formula next.
The reference it computed does not exist. Either the move went past the edge of the sheet, or height or width came out as 0 or negative. Put the row and column arguments in spare cells to see the numbers OFFSET is actually receiving - the fault is almost always in a COUNT or COUNTA that returned less than you expected.
Yes. Negative rows move up and negative cols move left, as long as the destination is still on the sheet. =OFFSET($D$10, -3, -2) returns B7. This is one of the few things OFFSET does that INDEX cannot express as directly.
INDEX, which also returns a reference and can sit on either side of a colon: $B$2:INDEX($B$2:$B$1000, COUNT($B$2:$B$1000)) is a non-volatile growing range. Excel Tables remove the need entirely for anything anchored to a data list, and in Microsoft 365 TAKE, DROP and the # spill operator cover most rolling-window cases.
Related Tools
INDIRECT Generator
The other volatile reference builder, for references assembled from text.
INDEX MATCH Generator
The non-volatile replacement for most dynamic ranges built with OFFSET.
COUNTA Generator
The count that usually drives an OFFSET height, and the gaps that break it.
Excel Chart Maker
Charts from a range or file, without maintaining a dynamic named range by hand.