The moment you apply the same transformation steps to more than one query, you are ready for Custom Functions. A custom function lets you write reusable logic once and call it from any query in the workbook. It works like a built-in Power Query function: call it by name, supply arguments, receive a result. Functions can return a single value — text, number, or date — or an entire transformed table. They are the foundation of any Power Query automation beyond simple single-table imports.
Custom Function Syntax
Every M function uses the same core syntax: a parameter list on the left of the arrow operator, and the expression to evaluate on the right. Functions are created as named queries in Power Query. They appear in the Queries pane with a function icon and are callable from any other query in the same workbook.
Three Ways to Create a Custom Function
Three distinct creation methods exist, each suited to a different scenario. Start with the simplest method that achieves the result — only escalate to more complex patterns when the simpler approaches are insufficient for the task.
- Blank Query (write from scratch) — Go to Data > Get Data > From Other Sources > Blank Query. Type the function syntax directly in the formula bar. Best for simple mathematical or text transformations where the pattern is already known.
- Promote from existing query — Build a query that transforms one sample file or table. Right-click the query and choose "Create Function". Power Query wraps the entire query into a reusable function automatically. This is specifically best for file-processing pipelines — CSV importers, PDF parsers, and Excel file transformers.
- Let expression (multi-step) — Write a full let...in block for functions involving intermediate variables, conditional logic, or table operations. This is the most powerful approach and handles functions returning tables or requiring complex input-type branching across many steps.
Example 1: VAT Calculator — Lookup Tax Rate from a Reference Table
A VAT calculation function takes a net price and a country code, looks up the correct rate from a reference table, and returns the gross price. Creating this once makes it reusable across all sales queries. Call it on every row of any orders table to apply the correct country-specific rate without repeating the lookup logic in each query. Furthermore, updating a rate in the reference table automatically applies the change to all queries that use the function — no per-query edits required.
Example 2: Multi-Format Date Parser — Normalise Inconsistent Date Strings
Data from different systems arrives with dates in different formats — "2025-01-15" from one database, "01-15-2025" from a US system, "15 January 2025" from a report export. A multi-format date parser function tries each format in a defined sequence, returning the first successful parse as a true date value. This single function normalises all date formats across any dataset, replacing a complex series of conditional columns with one clean function call per row.
Example 3: Multi-File Importer — One Function for a Whole Folder
This is the most common real-world use of Power Query custom functions. You have 12 monthly CSV files in a folder, all with identical structures but each requiring the same cleaning steps. Create the function once from a sample file. Power Query applies it to every file automatically. Furthermore, adding a new month's file to the folder and clicking Refresh imports it without any query changes — a fully automated pipeline that requires zero maintenance once built.
Example 4: Row Validation Checker — Flag Records with Data Quality Issues
A validation function checks each row against a set of quality rules and returns a text status message. Running it on every row flags records with missing values, out-of-range amounts, or invalid dates before data reaches downstream models. Consequently, quality issues are caught at the import stage rather than discovered weeks later in a report. The validation column makes filtered views of problem records immediately accessible without any additional steps.
Example 5: Address Formatter — Standardise CRM Contact Addresses
Address data from CRM systems is notoriously inconsistent — extra spaces, mixed case, and null values in some fields. A formatting function takes raw address components and returns a standardised single-line address. It handles null values gracefully, trims whitespace from each component, and applies consistent capitalisation rules. Applying this function to every row of a contacts table produces clean, uniformly formatted addresses for mail merge, shipping labels, and segmentation analytics.
Example 6: Invoke Custom Function — Apply via the Ribbon
The "Invoke Custom Function" option applies your function to every row through the ribbon, without writing any M code manually. Select the table query in the editor. Go to Add Column > Invoke Custom Function. Select your function name from the dropdown and map each parameter to a table column. Power Query generates the corresponding M code automatically and adds a new result column. This approach makes custom functions accessible to users who are not comfortable writing M expressions directly in the formula bar.
Troubleshooting Custom Functions
Both issues below are the most common causes of custom function errors in production queries. Null handling accounts for the majority of row-level errors across real data.
The function returns an error for some rows but not others
Row-level errors almost always mean the function is not handling null values correctly. If any row has a null in a column the function expects as text or number, M throws a type error for that row. Wrap null-sensitive operations with null checks: if value = null then null else DoSomething(value). Alternatively, use try MyFunction(value) otherwise "ERROR" to catch all errors and return a fallback value. Red cells in the Power Query preview indicate error rows — click one to see the exact error message identifying which parameter caused the failure.
The function is very slow when applied to large tables
Custom functions applied row-by-row can be slow because Power Query evaluates each row sequentially. Check whether the function logic can be replaced by a native Power Query column transformation applied to the entire column at once — Table.TransformColumns is often significantly faster than a row-by-row function call for simple text or number operations. Also verify the function does not perform a table join inside the row iterator, as this multiplies the join cost by the number of rows in the table and can cause severe performance degradation.
"Create Function" is missing from the right-click menu
The "Create Function" option only appears when the query contains a parameterisable input. If the option is missing, the query source is likely hard-coded. Convert the hard-coded path to a query parameter first: Home > Manage Parameters > New Parameter. Reference the parameter in the Source step. Then right-click the query again — the "Create Function" option will now appear in the menu and you can promote the parameter to a function argument.
Frequently Asked Questions
- How do I create a custom function in Power Query?+Go to Data > Get Data > From Other Sources > Blank Query. In the formula bar, type the function syntax: (parameter as type) => expression. For example: (price as number) => price * 1.20. Press Enter — the preview changes to show "Function". Name the query a meaningful name in the Queries pane. Call the function by name from any other query in the workbook, supplying arguments in parentheses, or use Add Column > Invoke Custom Function from the ribbon to map parameters visually.
- How do I apply a custom function to every row of a table?+Use Table.AddColumn with an each clause: Table.AddColumn(MyTable, "Result", each MyFunction([ColumnName])). The each keyword iterates over every row and evaluates the function for each one. Alternatively, use the ribbon: Add Column > Invoke Custom Function, select the function name, and map its parameters to table columns. Power Query generates the M code automatically and adds a result column for every row without any manual formula writing.
- Can a Power Query custom function return a table?+Yes. A Power Query function can return any M value type including a full table. Table-returning functions are particularly useful for file-processing pipelines — pass a binary file as input and the function returns the extracted and cleaned table. After calling the function and adding the result as a column, expand the column using the expand icon in the column header to flatten the returned tables into the main query's rows. This is the standard pattern for combining multiple source files using a custom transform function.
- Do Power Query custom functions update when source data changes?+Yes. Custom functions are M expressions stored in the workbook and re-evaluated every time you refresh the queries that call them. When source data changes and you click Data > Refresh All, every query calling the function runs the function logic again against the new data. The function definition only needs updating when the transformation logic itself changes — not when the underlying data changes. Update the function once and all calling queries benefit automatically on the next refresh.