Table.FromRows Function (Power Query M)

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 like type table[Name=text] (sets names and data types together), or a number that fixes the column count. When omitted, columns are named Column1, 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:

Column1Column2
Nairobi54
Lima47

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:

PlantStockLight
Fern30Shade
Lavender45Sun

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
StudentScore
Priya88
Marco74

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
NameKind
Studenttext
Scorenumber

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:

ShipmentIDCarrierCode
SH-204DLX
SH-205ARV
SH-206DLX

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:

ShipmentIDCarrierCodeCarrier
SH-204DLXDelExpress
SH-206DLXDelExpress
SH-205ARVArrow 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.FromRows does not check row lengths when it builds the table. Table.RowCount on 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 with Table.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 by Json.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:

I am a huge fan of Microsoft Excel and love sharing my knowledge through articles and tutorials. I work as a business analyst and use Microsoft Excel extensively in my daily tasks. My aim is to help you unleash the full potential of Excel and become a data-slaying wizard yourself.