Table.FromRows builds a table from a list of rows, where each row is itself a list of column values. Available in Excel (Power Query), Power BI Desktop, and Power BI Service.
If you want to create a small table right inside your M code, maybe a lookup table or a bit of test data, this is the function you reach for. No worksheet table or extra query needed.
Syntax of Table.FromRows Function
Table.FromRows(rows as list, optional columns as any) as table
where
rows(required, list). A list of inner lists. Each inner list holds the column values for one row, in column order.columns(optional, any). Accepts three shapes: a list of column names, a table type liketype table[Name=text](sets names and data types together), or a number that fixes the column count. When omitted, columns are namedColumn1,Column2, and so on.
Returns: a table with one row per inner list in rows. Unless you pass a table type, every column is created with type any.
In plain terms, you hand it your data one row at a time, and it hands you back a table.
Example 1: Create a table with default column names
The simplest call passes only the rows. Here each inner list is one city with its headcount.
let
Source = Table.FromRows({{"Nairobi",54},{"Lima",47}})
in
Source
The result is a two-row table with automatic column names:
| Column1 | Column2 |
|---|---|
| Nairobi | 54 |
| Lima | 47 |
Since no second argument was given, Power Query names the columns Column1 and Column2.
Example 2: Name the columns with a list
Default names are rarely what you want. Pass a list of names as the second argument.
This builds a small plant nursery stock table:
let
Source = Table.FromRows({{"Fern",30,"Shade"},{"Lavender",45,"Sun"}},{"Plant","Stock","Light"})
in
Source
The result now has proper headers:
| Plant | Stock | Light |
|---|---|---|
| Fern | 30 | Shade |
| Lavender | 45 | Sun |
The names list must have one entry per value in each row. And it sets names only, the columns still have no data types.
Example 3: Set column names and data types with a table type
To get typed columns straight away, pass a table type instead of a names list.
let
Source = Table.FromRows({{"Priya",88},{"Marco",74}},type table[Student=text,Score=number])
in
Source
| Student | Score |
|---|---|
| Priya | 88 |
| Marco | 74 |
The grid looks the same as a names list would give you. The difference is under the hood, so let’s prove it with Table.Schema:
let
Source = Table.FromRows({{"Priya",88},{"Marco",74}},type table[Student=text,Score=number]),
Schema = Table.SelectColumns(Table.Schema(Source),{"Name","Kind"})
in
Schema
| Name | Kind |
|---|---|
| Student | text |
| Score | number |
Each column carries its declared type. With a names list (Example 2), both Kind values would read any instead.
Example 4: Build an inline lookup table for a merge
This is the function’s most useful real-world job: a tiny reference table that lives inside the query, so you don’t need an extra worksheet table for two rows of mappings.
Say you have a Shipments query with carrier codes, and you want the full carrier names.
Here is the starting data:
| ShipmentID | CarrierCode |
|---|---|
| SH-204 | DLX |
| SH-205 | ARV |
| SH-206 | DLX |
Build the code-to-name lookup with Table.FromRows and merge it in with Table.NestedJoin. Then expand the carrier name with Table.ExpandTableColumn:
let
Source = Excel.CurrentWorkbook(){[Name="Shipments"]}[Content],
Carriers = Table.FromRows({{"DLX","DelExpress"},{"ARV","Arrow Van"}},{"CarrierCode","Carrier"}),
Merged = Table.NestedJoin(Source,"CarrierCode",Carriers,"CarrierCode","CarrierTable",JoinKind.LeftOuter),
Result = Table.ExpandTableColumn(Merged,"CarrierTable",{"Carrier"})
in
Result
Each shipment picks up its carrier name from the inline lookup:
| ShipmentID | CarrierCode | Carrier |
|---|---|---|
| SH-204 | DLX | DelExpress |
| SH-206 | DLX | DelExpress |
| SH-205 | ARV | Arrow Van |
Notice the row order. The join brings the matched groups out together, so the two DLX shipments now sit next to each other.
Example 5: See what happens when a row is too short
Every inner list must match the column count. Here the second row has one value for two columns, and the M below catches the exact error message when that cell is read:
let
Ragged = Table.FromRows({{"Brick",4},{"Tile"}},{"Item","Qty"}),
Attempt = try Ragged{1}[Qty],
Result = if Attempt[HasError] then Attempt[Error][Message] else Text.From(Attempt[Value])
in
Result
Result: 2 keys were specified, but 1 values were provided.
That message is what surfaces as an Expression.Error when the ragged row loads. The fix is simple: pad short rows with null so every inner list has the same length.
Things to keep in mind with Table.FromRows
- Construction is lazy, so ragged rows fail late.
Table.FromRowsdoes not check row lengths when it builds the table.Table.RowCounton a ragged table still succeeds, and the error from Example 5 only fires when the short row’s cells are actually read, often at load time. - Untyped columns cost you downstream. Columns typed
any(Examples 1 and 2) sort and compare unpredictably and won’t behave as numbers or dates in later steps. Pass a table type up front, or set types afterwards withTable.TransformColumnTypes. - A number as the second argument just pins the width.
Table.FromRows(rows,3)forces three columns with default names. Useful only when you want the count enforced without naming anything. - It never folds to the source. The table is built in memory by the mashup engine, which is exactly right for a small inline lookup. Don’t generate large tables this way; load them from a real source instead.
- Power BI’s Enter Data button generates this function. That intimidating
Table.FromRows(Json.Document(Binary.Decompress(...)))step in auto-generated queries is just your pasted data, compressed and encoded, then parsed back byJson.Document. Decode it or retype the data to edit it.
Common questions about Table.FromRows
What is the difference between Table.FromRows and #table?
They do the same job with swapped argument order. #table({"Item","Qty"},{{"Brick",4}}) is literal syntax with columns first; Table.FromRows is a regular function, which reads better when the rows come from another expression.
When should I use Table.FromRecords or Table.FromColumns instead?
Table.FromRecords takes a list of records, so each value is labelled with its field name and order doesn’t matter. Table.FromColumns takes one list per column. Use Table.FromRows when your data already arrives row-shaped, like parsed JSON arrays.
List of All Power Query Functions
Related Power Query Functions / Articles: