Power Query (M) Formatter

Paste the M code from Power Query's Advanced Editor and get each step, record and list laid out legibly. Formatting uses Microsoft's open-source M formatter running inside this page, so connection strings and file paths stay with you.

Input

Settings

History

Load from URL

Microsoft's formatter, in the browser

The engine is @microsoft/powerquery-formatter, the formatter Microsoft publishes alongside its Power Query language services for Visual Studio Code and the Power Query SDK. It parses M with Microsoft’s own parser, so it understands the complete language: let ... in expressions, records ([Name = "Sales"]), lists ({1, 2, 3}), each and _, custom functions with typed parameters, try ... otherwise, #date and #duration literals, quoted identifiers like #"Changed Type" and meta metadata.

Typical improvements over the single-line code the Advanced Editor produces after a few UI clicks:

  • every step of a let expression starts on its own line, indented under let
  • in and the returned step are placed on separate lines
  • long function calls are broken so each argument, record field or list item is readable
  • nested records such as the options of Csv.Document or Web.Contents expand when they do not fit

Step names, string contents, comments and the order of steps are never changed.

Indentation, width and shortcuts

There are no M-specific options. The toolbar’s indent setting becomes the formatter’s indentation (spaces or a tab), and the line width tells it when to break a call or a record across lines. The Advanced Editor in Excel and Power BI Desktop uses a proportional font by default, so a slightly narrower width often reads better there than the 80 columns the toolbar starts with.

Press Ctrl/Cmd+Enter to format, then Ctrl/Cmd+Shift+C to copy the result back into the Advanced Editor. Ctrl/Cmd+K opens the command palette if you also need the DAX formatter for the model side. Ctrl/Cmd+Shift+M (minify) is not available for M.

Errors and practical notes

The parser is strict, which is useful: an error here is usually an error Power Query would report too, but with a clearer position. Messages name what the parser expected and what it found, for example a right parenthesis where the keyword in was found, which means a call was not closed before the end of the let block.

Two mistakes account for most failures. The first is a comma after the last step, just before in — Power Query does not allow it. The second is a missing comma between two steps after editing code by hand. Both are reported at the right line.

Folder paths and URLs inside strings are left exactly as written, including backslashes. Comments written with // or /* */ are preserved. If you are pulling data from a CSV, the CSV formatter helps check the source file’s delimiter and quoting before you write the M to import it.

Examples

Web API to table

The options record of Web.Contents expands field by field; short steps stay on one line.

Input
let Source=Json.Document(Web.Contents("https://api.example.com",[RelativePath="orders",Query=[status="paid"]])),Items=Source[data],AsTable=Table.FromRecords(Items),Renamed=Table.RenameColumns(AsTable,{{"created_at","Created"},{"total","Total"}}) in Renamed
Output
let
    Source = Json.Document(
        Web.Contents(
            "https://api.example.com",
            [
                RelativePath = "orders",
                Query = [status = "paid"]
            ]
        )
    ),
    Items = Source[data],
    AsTable = Table.FromRecords(Items),
    Renamed = Table.RenameColumns(
        AsTable, {{"created_at", "Created"}, {"total", "Total"}}
    )
in
    Renamed
Open this example in the tool

Custom function with optional parameter

The signature stays on the first line and the let body is indented beneath it.

Input
(start as date,optional days as nullable number)as list=>let n=if days=null then 7 else days,dates=List.Dates(start,n,#duration(1,0,0,0)) in List.Select(dates,each Date.DayOfWeek(_,Day.Monday)<5)
Output
(start as date, optional days as nullable number) as list =>
    let
        n = if days = null then 7 else days,
        dates = List.Dates(start, n, #duration(1, 0, 0, 0))
    in
        List.Select(dates, each Date.DayOfWeek(_, Day.Monday) < 5)
Open this example in the tool

Group and sort, 4-space indent

The aggregation list of Table.Group is split one aggregation per line.

Input
let Source=Excel.CurrentWorkbook(){[Name="Sales"]}[Content],Grouped=Table.Group(Source,{"Region"},{{"Revenue",each List.Sum([Amount]),type number},{"Orders",each Table.RowCount(_),Int64.Type}}),Sorted=Table.Sort(Grouped,{{"Revenue",Order.Descending}}) in Sorted
Output
let
    Source = Excel.CurrentWorkbook(){[Name = "Sales"]}[Content],
    Grouped = Table.Group(
        Source,
        {"Region"},
        {
            {"Revenue", each List.Sum([Amount]), type number},
            {"Orders", each Table.RowCount(_), Int64.Type}
        }
    ),
    Sorted = Table.Sort(Grouped, {{"Revenue", Order.Descending}})
in
    Sorted
Open this example in the tool

Common errors and how to fix them

ErrorCauseFix
Expected to find a right parenthesis <')'>, but a keyword <'in'> was found insteadA function call inside a step was not closed before the in keyword.Add the missing ) at the end of the step the error points to.
A comma cannot proceed an 'in'The last step before in ends with a comma. (The wording is the parser’s own.)Delete the comma after the final step.
Unterminated stringA text literal is missing its closing double quote.Close the string. Quotes inside M strings are escaped by doubling them (“”).
Expected to find one of the following, but the end-of-stream was reached insteadThe query stops in the middle of an expression, for example in with nothing after it.Add the name of the step to return after in, or finish the incomplete expression.

Frequently asked questions

Where do I get the M code to format?

In Excel or Power BI Desktop open Power Query, select the query and choose Advanced Editor. Copy everything, format it here and paste it back.

Will formatting change what my query does?

No. Only whitespace and line breaks change. Step names, their order and every literal are kept.

Does it support Power Query in Dataflows and Fabric?

Yes. Dataflows, Fabric and Excel all use the same M language, so code from any of them formats the same way.

Is this the formatter used in VS Code?

It is the same open-source @microsoft/powerquery-formatter package that Microsoft’s Power Query tooling uses.

Related tools