Read our blogs, tips and tutorials
Try our exercises or test your skills
Watch our tutorial videos
Catch up on one of our webinars
Take a self-paced course
Read our recent newsletters
License our courseware
Book expert consultancy
Buy our publications
Get help in using our site
400 attributed reviews in the last 3 years
Refreshingly small course sizes
Outstandingly good courseware
Whizzy online classrooms
Wise Owl trainers only (no freelancers)
Almost no cancellations
We have genuine integrity
We invoice after training
Review 30+ years of Wise Owl
View our top 100 clients
Search our website
We also send out useful tips in a monthly email newsletter ...
Some other pages relevant to these blogs include:
You can also book hourly online consultancy for your time zone with one of our 7 expert trainers!
|
Creating user-defined DAX functions in Power BI Part two of a two-part series of blogs |
|---|
|
You've been able to create your own DAX functions in Power BI for a while, but now that this feature has emerged from preview we thought it would be a good time to do a deep dive into how you can create your own custom DAX functions.
|
In this blog
The previous part of this blog hid one bit of complexity: the parameter mode specification for any argument.
I'm going to start at the end point this time - here's the visual we want to create:

We'll create a DAX function to create these measures.
Here are the measures I've created:

I've created a separate table to hold my 3 measures.
And here's an example of one of my measures (they all follow the same format):

The measure uses a function called CountFilmsOver which we'll create below. Notice the way that Intellisense underlines the RunTimeMinutes column as an error, even though this will work).
A big warning: you should only consider creating user-defined functions passing parameters as expressions in DAX if you already have a good understanding of creating measures, and also a good understanding of filter and row context.
Here's what the function to count films could look like:
DEFINE
FUNCTION CountFilmsOver = (
// EXPR means we'll use lazy loading - see below
ValueToTest : NUMERIC EXPR,
MaxValue : NUMERIC VAL
) =>
// we return the number of rows from the film table
// where the passed in expression exceeds the passed
// in threshold
COUNTROWS(
FILTER(
Film,
ValueToTest > MaxValue
)
)
EVALUATE
{
// testing our function to show the number
// of films lasting more than 2.5 hours
CountFilmsOver(
Film[RunTimeMinutes],
150
)
}
Because we haven't assigned types or subtypes to our parameters, DAX will allow them to have any type and any value (which in this case is what we want).
Here's what this query would show if you ran it:

There are 201 films lasting longer than 150 minutes.
Suppose that you replaced the word EXPR with VAL
FUNCTION CountFilmsOver = (
// Here we've used VAL, not EXPR, for the first parameter
ValueToTest : NUMERIC VAL,
MaxValue : NUMERIC VAL
) =>
If you run the same query you now get this error:

The error message you'll get.
The reason is that VAL implies that you will be using eager loading. What this means is that DAX will try to evaluate the expression being passed into the parameter before passing it. There is no context when you run the query, so DAX is complaining that it can't possibly know what the film run time minutes are. When you change VAL back to EXPR DAX uses lazy loading, and only evaluates the expression within the function (at which time it does have context).
The rules on context transition when you pass parameters as expressions to DAX functions are particularly complicated! My advice would be to avoid creating DAX functions passing expressions and stick to passing parameters as VAL, at least until such point as you consider yourself a DAX guru.
| Parts of this blog |
|---|
|
Some other pages relevant to these blogs include:
You can also book hourly online consultancy for your time zone with one of our 7 expert trainers!
Kingsmoor House
Railway Street
GLOSSOP
SK13 2AA
Landmark Offices
6 Bevis Marks
LONDON
EC3A 7BA
c/o Holiday Inn
25 Aytoun Street
MANCHESTER
M1 3AE
© Wise Owl Business Solutions Ltd 2026. All Rights Reserved.