
You have product totals in column A and service totals in column D. You want one tidy list — totals from A stacked on top of totals from D — to feed into a SUMIFS or a chart. The usual move is to copy both ranges into a helper column and live with the duplicate data. Curly braces let you skip that step. A single formula like ={A2:A20; D2:D20} stitches the two ranges into one virtual column and spills the result downward. The braces are an array literal: a small, on-the-fly array you build inside any formula. They look strange at first. Once the grammar clicks, you reach for them every week.
What the braces actually do
An array literal is a chunk of data you write directly into a formula, wrapped in { }. Inside the braces, two separators do all the structural work: a comma starts a new column, and a semicolon starts a new row. Read the punctuation as layout, and the formula stops being mysterious.
Type ={1, 2, 3} into any cell. Three values spill across one row. Now try ={1; 2; 3} — the same three values, one column. Combine them with ={1, 2; 3, 4} and you get a 2×2 grid. Every literal you build sits somewhere on that comma / semicolon scale.
| A | B | C | |
|---|---|---|---|
| 1 | ={“Item”,”Qty”,”Price”} | Qty | Price |
| 2 | Item | Qty | Price |
The formula in A1 — a literal of three strings — spills “Item”, “Qty”, and “Price” across A1:C1. The header row appears in one keystroke instead of three. Numbers, text, dates, and TRUE/FALSE all live happily inside the braces; the only thing the literal cannot store is another array of unequal length, which we handle in the errors section below.
Stacking ranges in one shot
The literals get genuinely useful the moment you put cell references inside them. A semicolon between two ranges welds them into one virtual column. A comma welds them into one virtual row. The result spills like any other array formula.
Copy A2:A100 and D2:D100 into helper column F, then =SUM(F:F).
Two manual copy-pastes you have to redo whenever the data grows.
=SUM({A2:A100; D2:D100})
One formula. Grows with the ranges.
Same trick, run sideways:
={A2:A100, D2:D100}
That drops column A and column D side by side, in that order. Useful when you want to feed a two-column input into VLOOKUP or QUERY without rearranging the source sheet. Want a header above the stack? Nest the header literal inside the outer literal:
={"Amount"; A2:A100; D2:D100}
One column, header in row 1, A’s values, then D’s values. The whole literal is one formula in one cell, and it spills to fill the height it needs. For more on chaining arrays into reusable shapes, the deeper write-up on array formulas in Google Sheets picks up where this section ends.
When commas turn into backslashes
Type ={1, 2, 3} in a sheet set to Germany or Brazil and you get #ERROR!. The fix is not the formula — it’s the locale. In countries where the decimal mark is a comma, Sheets swaps the array separators so the parser can still tell numbers apart from structure.
| Locale group | New column | New row | Example |
|---|---|---|---|
| US, UK, India, Japan | , |
; |
={1, 2; 3, 4} |
| Germany, France, Spain, Brazil | \ |
; |
={1\ 2; 3\ 4} |
One practical consequence: a formula copied from a tutorial — or from another sheet — fails the moment the source and destination locales disagree. The error is loud (#ERROR!, not a quiet wrong number), so you spot it immediately. The diagnosis is simple: when an array literal blows up in a sheet that should accept it, locale is the first suspect. The official Google Docs help page on array literals documents the full separator matrix per region.
Decoding dimension errors
Once you start putting real ranges inside braces, you meet a new family of errors. They all come from one cause: the array you described is impossible to lay out in a rectangle.
The two messages you’ll see most:
={A2:A10, B2:B20}
# In ARRAY_LITERAL, an Array Literal was missing values for one or more rows.
You asked for two columns side by side, but column A has 9 rows and column B has 19. Sheets cannot finish row 10. Trim both ranges to the same height: ={A2:A10, B2:B10}.
={A2:A10; B2:C10}
# In ARRAY_LITERAL, an Array Literal was missing values for one or more rows.
Both ranges have ten rows, but they have different column counts — one column on top of two. A vertical stack needs the same number of columns in every layer. Grab both columns from the top range, ={A2:B10; B2:C10}, or drop the bottom range to one column.
A quick mental check before you press Enter: count the columns on each side of every semicolon. They must match. Count the rows on each side of every comma. They must match too. The rectangle rule is the whole thing.
Pairing arrays with FILTER, SORT, and QUERY
This is where literals stop being a syntax curiosity and start replacing whole helper sheets. Three functions use them constantly.
FILTER with multiple keyword matches. The classic OR-condition: rows where Status is open or in progress. Without literals, you write two FILTER conditions joined by addition. With literals, you write the values inline:
=FILTER(A2:C100, REGEXMATCH(B2:B100, TEXTJOIN("|", TRUE, {"open","in progress"})))
The literal {"open","in progress"} is the OR list. Add a third status next quarter? Add a comma and a string. No formula restructure.
QUERY with hard-coded headers. Stacking a header row on top of a headerless QUERY result is a one-line job:
={"Customer","Total"; QUERY(A:D, "select A, sum(D) where A is not null group by A label sum(D) ''", 1)}
The outer literal puts row 1 (the two strings) above the QUERY block. You get clean column titles without touching the source data. The walkthrough of QUERY for SQL-style analysis covers the inner pattern in detail.
SORT on a built column. Sometimes you want to sort by a value that isn’t stored anywhere — say, the absolute size of a change. Build the column inline:
=SORT(A2:B100, ABS(B2:B100), FALSE)
Strictly, that one doesn’t need braces — but the moment you sort by two derived columns, you do: {ABS(B2:B100), C2:C100-D2:D100} as the sort key. The literal is the only way to hand SORT a multi-column key it didn’t already see on the sheet.
When the helper column still wins
Array literals are not a free upgrade. They concentrate logic into one cell, which is sometimes the wrong move.
- ✓ Skip the braces when three people will edit the formula — a helper column reads in seconds
- ✓ Skip them on sheets above 50,000 rows, where SUM over a literal becomes the slowest cell
- ✓ Skip them when the input ranges live on different tabs with different headers — the readability cost spikes
- ✓ Use them when the literal sits inside a named function — the awkwardness is hidden once
The performance gap is real but small at moderate size. A SUM({A2:A1000; D2:D1000}) takes essentially the same time as SUM(F2:F2000) with F as a helper. Above 50,000 rows, the literal version recomputes the stacked array on every dependency change, while the helper column is cached. If your file is approaching the documented 10-million-cell ceiling, treat literals as a debugging aid only.
The judgment call is rarely about milliseconds. It’s about the person who opens the sheet six months from now. A helper column they can scan beats a literal they have to mentally unroll — even when the literal is technically tighter. Save the braces for the formulas that genuinely shorten themselves.
Where to use them tomorrow
Look for two patterns in your existing sheets: a helper column that just stacks two ranges, and a FILTER or QUERY that lists alternatives with repeated OR conditions. Both shorten to a single literal. Try one swap per file, watch how it reads to a coworker, and decide whether the trade is worth it before going wider.
The braces are not for every formula. They’re for the formulas where reaching for a separate column always felt like one step too many.
