November 4, 2025

Power BI User-Defined Functions

By Dave Ovitt

Anyone who has worked with dynamic color measures using Power BI knows the pain of creating 150 measures in Power BI, waiting for the model to validate after pasting in the copied DAX from the original measure, and updating filter variables. 

First, we jumped to using the Tabular Editor, skipping around all of the waiting for those validation sequences. But oh no, now the measure logic needs to be changed, and I have to open each of those measures again, make updates, and then check 15 times to be sure that I updated everything correctly. Well, the time has come for User-Defined Functions!

In this blog, we will discuss User-Defined Functions in Power BI, how to enable them in Power BI Desktop, and walk through examples of how to start using them in both TMDL and DAX views. 

What are User Defined Functions in Power BI?

User-Defined Functions (UDFs) are a preview feature released in the September 2025 update for Power BI, that allow you to package and reuse common DAX logic in a semantic model, including the passing type-specific parameters so that the logic can be reused with minimal change needed as updates to business logic change. 

How to Enable UDFs in Power BI?

To enable UDF’s in Power BI Desktop, you need to go to Options and Settings > Preview Features and enable DAX user-defined functions. 

Once this is applied, restart Power BI, and you will be able to create and update UDFs.

How Should You Leverage UDFs in Power BI?

The first step in using UDFs is identifying a use case for your function. It should be logical that it is parameter-dependent and will be reused across multiple measures, calculated columns, visual calculations, or other UDFs. An easy example would be the percent difference between two values.

We must first define the measure, using TMDL or DAX Query View. Let’s give an example of both!

Defining a UDF using DAX Query View

The format for creating a UDF in DAX Query is

				
					 DEFINE
/// Optional description above the function
    FUNCTION <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>
				
			

And the types for parameters are 

Type: (AnyVal, Scalar, Table, or AnyRef).

Subtype (only for scalar type): (Variant, Int64, Decimal, Double, String, DateTime, Boolean, or Numeric)

So if we define percent change as (x-y) ÷ x, where x represents the original value and y represents the new value, we know that we need to make numeric parameters to represent the values for x and y. So the UDF would look like this in DAX View

				
					DEFINE
    ///UDF to Find Percentage Change between two values
    FUNCTION PercentChange = (OriginalValue : numeric, NewValue :numeric) =>
    DIVIDE((OriginalValue-NewValue),OriginalValue,0)
				
			

You will then see a notice in the code asking you to update the model. You can do this by selecting the note or by selecting Update model with changes.

Once this is in the model, you can evaluate the UDF in DAX Query View

				
					EVALUATE
{PercentChange(100,50)}
				
			

Defining a UDF Using TMDL View

Similar to DAX Query View, you can use TMDL View to create UDFs, but with small changes in context. The format is as follows:

				
					createOrReplace
/// Optional description above the function
    FUNCTION <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>
				
			

So, for our PercentChange UDF, we would write 

				
					createOrReplace
    ///UDF to Find Percentage Change between two values
    function PercentChange = (OriginalValue : numeric, NewValue :numeric) =>    DIVIDE((OriginalValue-NewValue),OriginalValue,0)
				
			

TMDL can be particular about spacing and text formatting, but as you start typing, the format should populate for you with code tooltips to assist your development. 

Once you are done writing your UDF, click Apply to save changes to the model.

If you want to evaluate this UDF, though, you will need to go back to DAX Query View or use it in a Measure, Calculated Column, or Visual Calculation. We’ll talk about how to do that next!

Calling a UDF

UDFs can be called from Measures, Calculated Columns, Visual Calculations, and other UDFs. Let’s look at some of the ways to do this!

Calling a UDF From a Measure

Using a UDF inside a measure is really easy, but you must understand what values you are passing to the UDF. If your parameter is intended to be a single value, your measure must ensure that the values being passed to the UDF are aggregated. 

Let’s create a measure for using our UDF on the built-in sample financial data in Power BI Desktop:

				
					UseThisUDF =
VAR Sales = SUM(financials[Sales])
VAR Profit = SUM(financials[Profit])
RETURN PercentChange(Sales,Profit)

				
			

By aggregating the Sales and Profit column before passing the values to the UDF, the measure is able to be evaluated in visuals without concern that the parameters will throw an error. 

Calling a UDF from a Calculated Column

Because UDFs return a variant type by default, we must use a CONVERT function to ensure the data type is defined. 

				
					LineDiscountPercent = CONVERT(PercentChange(financials[Gross Sales],financials[Sales]),DECIMAL)
				
			

Calling a UDF from a Visual Calculation

While using a UDF in a Visual Calculation, you may see issues with the function suggestions, but the UDFs still work! You must keep in mind that visual calculations can only use the fields present in the visual, so nested calculations where the values aren’t present in the visual will cause issues with the UDF.

				
					% Discount = PercentChange([Sum of Gross Sales],[Sum of Sales])

				
			

Calling a UDF from another UDF

Lastly, we are going to nest a UDF inside of another UDF. This will pass the first parameter provided to the AddShippingAndDiscount UDF to the AddShipping UDF that is nested inside. While nesting UDFs, take care to ensure that the parameters match types across all UDFs. 

				
					DEFINE
    /// AddShipping Estimate takes in amount and returns estimated shipping
    FUNCTION AddShipping =
        ( amount : NUMERIC ) =>
            amount + 50

    /// Uses Addshipping and a discount to give out the door price
    FUNCTION AddShippingAndDiscount =
        (
            amount : NUMERIC ,
            discount : NUMERIC
        ) =>
            AddShipping ( amount - discount )
           
EVALUATE
{ AddShippingAndDiscount(1000,50)}

				
			

Best Practices

Closing

User-Defined Functions are a game-changer for DEVs who utilize standardized formatting and functions across Power BI, and when these are combined with Scalable Vector Graphics (SVGs), they allow for consistent, customized visuals that can be easily reused across reports.

phData Blue Shield

Transform your reporting with Power BI

If you’re looking to scale your Power BI reporting or streamline how your organization builds and maintains dashboards, phData’s experts can help. Our team specializes in optimizing data workflows and building scalable, impactful Power BI solutions.

FAQs

This preview feature came out in September 2025, and needs to be enabled under Options and Settings > Preview Features, and then Power BI must be restarted before you can create them. Be sure you are using the latest version of Power BI to test these functions!

While calculating most things as close to the data source as possible is best practice, some values must be calculated with the context of the visual they’re in, and UDF’s allow for consistent coding across multiple measures and visualizations, but as with all analytics solutions, the quality you retrieve from UDFs will correlate to the effort put in to defining it. Be sure to define your parameters correctly, follow best practices for creating and using measures, and be especially careful when using calculated columns for anything.

Data Coach is our premium analytics training program with one-on-one coaching from renowned experts.

Accelerate and automate your data projects with the phData Toolkit