Lookup and reference functions
OFFSET
Matches all 7 recorded answers
Recorded: 7 workbook cells. How we measure this · See the Rust code
Local names in 40 languages
| Language | Name in Excel |
|---|---|
| Arabic | OFFSET |
| Bulgarian | OFFSET |
| Czech | POSUN |
| Danish | FORSKYDNING |
| German | BEREICH.VERSCHIEBEN |
| Greek | OFFSET |
| English (Australia) | OFFSET |
| English (United Kingdom) | OFFSET |
| English (United States) | OFFSET |
| Spanish | DESREF |
| Estonian | OFFSET |
| Finnish | SIIRTYMÄ |
| French | DECALER |
| Hebrew | OFFSET |
| Croatian | OFFSET |
| Hungarian | ELTOLÁS |
| Indonesian | OFFSET |
| Italian | SCARTO |
| Japanese | OFFSET |
| Korean | OFFSET |
| Lithuanian | OFFSET |
| Latvian | OFFSET |
| Norwegian | FORSKYVNING |
| Dutch | VERSCHUIVING |
| Polish | PRZESUNIĘCIE |
| Portuguese (Brazil) | DESLOC |
| Portuguese (Portugal) | DESLOCAMENTO |
| Romanian | OFFSET |
| Russian | СМЕЩ |
| Slovak | OFFSET |
| Slovenian | OFFSET |
| Serbian (Latin) | OFFSET |
| Swedish | FÖRSKJUTNING |
| Thai | OFFSET |
| Turkish | KAYDIR |
| Ukrainian | OFFSET |
| Vietnamese | OFFSET |
| Chinese (Simplified) | OFFSET |
| Chinese (Hong Kong) | OFFSET |
| Chinese (Traditional) | OFFSET |
Names from Microsoft's support site.
What it does
OFFSET(reference, rows, cols, [height], [width])
OFFSET is one of the few worksheet functions whose result is a reference, not a value.
It performs arithmetic in the address space of the grid.
Given a base reference B whose top-left cell is at row r₀ and column c₀, and whose
extent is h₀ × w₀, together with displacements Δr and Δc and optional dimensions h and
w, OFFSET returns the rectangular area
- whose top-left cell is at row
r₀ + Δrand columnc₀ + Δc, - with height
h(defaulth₀) and widthw(defaultw₀).
Note precisely what the defaults mean: the returned area inherits the base reference's
shape, not a single cell. OFFSET(A1:C3, 1, 1) is B2:D4, a 3×3 area — not B2. This is
the detail that most surprises readers who think of OFFSET as "the cell n down from here".
Microsoft states the other half explicitly: OFFSET does not move any cells or change the
selection; it computes an address. What happens to that address afterwards is the caller's
business — a consuming function resolves it, an aggregate scans it, a cell publishes its
contents (or spills them).
The value of OFFSET is that its displacement and its size are computed. OFFSET(A1, 0, 0, COUNTA(A:A), 1) is a range whose length tracks the data — the classic dynamic-range idiom,
and the reason OFFSET outlived several attempts to replace it.
Arguments
reference — the base. Must be a single cell or a contiguous range; a multi-area union is
rejected. Its size supplies the defaults for height and width.
rows — vertical displacement, positive downward, negative upward.
cols — horizontal displacement, positive rightward, negative leftward.
height — optional row count of the result, defaulting to the base reference's height.
width — optional column count of the result, defaulting to the base reference's width.
Try it
Quirks
Result and edge cases
The result kind is ReferenceLike — an A1 shape when the computed extent is a single cell,
an Area shape otherwise. This matters because a reference can be consumed in ways a value
cannot: it can be handed to SUM, to ROWS, to CELL("address", …), or to the : range
operator, and it can be resized again.
- Published into a cell, an area-shaped result is materialized: on a modern Excel it
spills; on the legacy grid model an unrequested area produced a
#VALUE!unless entered as an array formula. Which of those a reader sees is a property of the host and the workbook's calculation surface, not ofOFFSET. - Displacement off the grid is an error, not a clamp. Moving before row 1 or column A, or
past the last row or column, yields
#REF!. - A base reference on another sheet displaces within that sheet;
OFFSETcarries the sheet identity of its base. - Reference resolution and the values-versus-references distinction are described once in
the call pipeline, stage 1;
OFFSETis one of the namedRefsVisibleInAdapterfunctions there.
Volatility
OFFSET is volatile. It is recomputed on every recalculation of the workbook, whether or
not any cell it depends on has changed, and everything downstream of it is recomputed too.
This is not an implementation choice that could be optimized away. OFFSET's arguments name a
displacement, so the engine cannot know which cells the result will designate until it has
evaluated the function — the dependency graph cannot be built statically from the formula
text. Volatility is the price of that late binding.
The practical consequence is that OFFSET used at scale is a recalculation cost multiplier: a
few thousand volatile cells, each with a dependent subtree, is a workbook that pauses on every
edit. The usual modern replacements are:
- structured table references (
Table1[Amount]), which grow with the table and are not volatile; INDEX, which returns a reference from an explicit range and is not volatile — theA1:INDEX(A:A, n)idiom builds a dynamic range without volatility;- spill anchors (
B1#), which reference a dynamic array's current extent directly; TRIMRANGEand the trim-reference operators, for the specific case of "the used part of this column".
Errors
Documented by Microsoft:
| Error | Documented condition |
|---|---|
#VALUE! | reference is not a cell or a contiguous range (for example, a multi-area union) |
#REF! | rows and cols displace the reference over the edge of the worksheet |
How to implement
Notes for implementers
- The first argument must arrive reference-bearing. If argument preparation dereferences it, the function cannot be written: there is no address left to displace.
- The result must be a reference, not the values at that address. A tempting shortcut is to
materialize the area and return an array; it produces the right numbers in
SUM(OFFSET(...))and the wrong answer everywhere the reference identity is observed —CELL("address", OFFSET(...))is the cheap test. - Default
heightandwidthcome from the base reference's extent, which means the function needs the base's shape, not just its top-left cell. - Volatility must be declared, not inferred. An engine that constant-folds
OFFSETbecause all its arguments are literals will produce a stale reference after a row insertion.
Rust code
Show the CalcFunc source of this function
Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.
OFFSET · 15 lines · calc-func/src/catalogue/offset.rs on GitHubCatalogueEntry {
id: OFFSET,
spelling: "OFFSET",
notation: Notation::Call,
arity: CallableArityShape::range(3, 5),
parameters: &[
Parameter::reference("reference"),
Parameter::value("rows"),
Parameter::value("cols"),
Parameter::value("height"),
Parameter::value("width"),
],
demand: ArgumentDemand::Eager,
kernel: Kernel::Eager(offset),
}
offset · 18 lines · calc-func/src/catalogue/offset.rs on GitHubfn offset(
arguments: &[CalcValue],
services: &mut EvalServices<'_>,
) -> Result<CalcValue, FunctionFault> {
// dc-ylr: Excel gives OFFSET of a reference to a closed workbook #VALUE!.
let external = arguments[0].as_reference().is_some_and(|reference| {
reference.areas().iter().any(|area| {
services
.host()
.is_some_and(|host| host.is_external_sheet(area.sheet()))
})
});
let site = Site::new(OFFSET, services);
if external {
return Site::finish(Err(Exit::Error(WorksheetErrorCode::Value)));
}
Site::finish(shifted(&site, arguments))
}
shifted · 28 lines · calc-func/src/catalogue/offset.rs on GitHubfn shifted(site: &Site<'_>, arguments: &[CalcValue]) -> Step<CalcValue> {
site.scalar_operands(arguments)?;
let Some(reference) = arguments[0].as_reference() else {
return Err(Exit::Error(WorksheetErrorCode::Value));
};
let [base] = reference.areas() else {
return Err(Exit::Error(WorksheetErrorCode::Value));
};
let rows = whole(site, 1, &arguments[1])?;
let cols = whole(site, 2, &arguments[2])?;
let height = extent(site, 3, arguments.get(3), base.row_count())?;
let width = extent(site, 4, arguments.get(4), base.column_count())?;
let top = i64::from(base.first().row()) + rows;
let left = i64::from(base.first().column()) + cols;
let (top, bottom) = span(top, height);
let (left, right) = span(left, width);
let on_grid = |low: i64, high: i64, max: u32| low >= 1 && high <= i64::from(max);
if !on_grid(top, bottom, MAX_ROWS) || !on_grid(left, right, MAX_COLUMNS) {
return Err(Exit::Error(WorksheetErrorCode::Ref));
}
let sheet = base.sheet();
let corner = |row: i64, column: i64| {
CellKey::new(sheet, row as u32, column as u32).expect("checked on the grid")
};
let area = GridArea::new(corner(top, left), corner(bottom, right))
.expect("both corners lie on one sheet");
Ok(CalcValue::reference(ReferenceLike::area(area)))
}
whole · 6 lines · calc-func/src/catalogue/offset.rs on GitHub/// Argument `index` read as a number and truncated toward zero; a value beyond any grid offset
/// is kept large enough to leave the grid.
fn whole(site: &Site<'_>, index: usize, value: &CalcValue) -> Step<i64> {
let n = site.number_argument(index, value)?.trunc();
Ok(n.clamp(-4_000_000.0, 4_000_000.0) as i64)
}
extent · 12 lines · calc-func/src/catalogue/offset.rs on GitHub/// The height or width argument `index`, truncated: the reference's own `own` when it is not
/// given, #REF! when it is 0.
fn extent(site: &Site<'_>, index: usize, value: Option<&CalcValue>, own: u32) -> Step<i64> {
match value {
None => Ok(i64::from(own)),
Some(value) if value.is_missing() => Ok(i64::from(own)),
Some(value) => match whole(site, index, value)? {
0 => Err(Exit::Error(WorksheetErrorCode::Ref)),
n => Ok(n),
},
}
}
Kernels shared with other functions
spancatalogue/offset
Argument and result plumbing
Parameter::referencecatalogueParameter::valuecatalogue
No implementation has been published with a Handbook test suite for this function.
Version differences
No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.
Alternatives
Relationships
INDEXis the closest sibling and the recommended replacement for most dynamic-range work: it also returns a reference, but from an explicit range and without volatility.INDIRECTis the other reference-producing function, and is also volatile; it builds a reference from text, which is strictly more dangerous and strictly less analyzable.ROW,ROWS,COLUMN,COLUMNS,CELL,ADDRESSare the rest of the reference-inspection family;OFFSETis the reference-producing member.TRIMRANGEand the trim-reference operators occupy some of the groundOFFSETwas used for — trimming a whole-column reference down to its populated extent — without volatility.- Readers confuse
OFFSETwithINDEX's reference form (which selects within a range rather than displacing from it) and withINDIRECT.
Named variants
No named variants are recorded yet.
Suggest a correction or contribute an implementation · For agents