Almanac
Microsoft/power-appsPower Platform

Consultant KB for Microsoft Power Apps: canvas apps, model-driven apps, Power Fx, data and connections, controls and UI, code and extensibility, mobile and offline, ALM and solutions, governance and security, licensing and performance, plus cross-cutting decision guides. Implementation notes, configuration decisions and the gotchas that bite on real projects. Populated by the daily author agent from the Power Apps release plans, docs repo and product blog, plus the author's own consultant notes.

feature-user-defined-functions-and-types.mdv1 · history
CurrentApplies to BothUpdated last monthSource Microsoft Learn

What it does

User-defined functions (UDFs) let you write your own Power Fx functions with typed parameters and a typed return value, defined in App.Formulas alongside named formulas. User-defined types (UDTs) let you name a record or table shape with the Type function so those functions can take and return structured data.

Key facts

  • Both are generally available. UDFs reached GA in September 2025 with Power Apps Studio 2508.3, and UDTs reached GA in May 2026 with Studio version 3.26044.
  • UDTs are on by default for new apps. For existing apps you enable them under Settings > Updates > New > User-Defined types.
  • UDFs depend on the new analysis engine, which is why the two switches were combined at GA. It's on by default for new apps.
  • Syntax is FunctionName( Param: Type ) : ReturnType = Formula;. Every parameter and the return value must be typed — there's no inference here, unlike named formulas.
  • Types are defined with := rather than =, for example Book := Type( { Title: Text, Author: Text } ). RecordOf extracts the record type from a table type.
  • Behaviour UDFs are supported by wrapping the body in curly braces and chaining statements. Use Void as the return type when the function doesn't return a value.
  • Record matching for parameters is stricter than elsewhere in Power Fx. The fields of a value must be a proper subset of the type and can't include extras — passing a record with a spare column is an error.
  • Recursion isn't supported.
  • UDTs work with ParseJSON, IsType and AsType, which is where they earn their keep — a typed ParseJSON validates and converts ISO 8601 date strings instead of handing you text.

When to use / skip

Use UDFs the moment the same logic appears in three control properties. That's the point where duplication starts drifting out of sync, and a UDF is easier to reason about and test in isolation than the same expression scattered across a screen. Use UDTs when you're passing records or tables around, and always when you're parsing JSON from a connector — untyped JSON handling in Power Fx was miserable before this and there's no reason to keep doing it. Skip both for a two-screen app that one person maintains; the ceremony isn't worth it.

Configuration decisions

  • Whether existing apps get the UDT switch turned on, and whether that happens per app or as an estate-wide standard.
  • Where the boundary sits between a named formula, a UDF, and a component with enhanced properties, since all three now do reuse and they overlap.
  • Which types are defined centrally and treated as the app's data contract, versus defined ad hoc next to the function that uses them.
  • How you handle logic that wants recursion, given the language doesn't offer it.

Gotchas

  • The strict record matching bites when you pass something straight out of a gallery selection or a form. Extra columns that Power Fx tolerates everywhere else are rejected here, and the error doesn't obviously point at the extra field.
  • Behaviour UDFs don't stop on error by themselves. Execution continues past an Error call in a chained body unless you gate it with If or IfError.
  • Everything lives in App.Formulas, so functions, types and named formulas all share one unstructured text property. Large apps end up with a very long single property and no navigation.
  • Existing apps don't get UDTs automatically. If a maker copies a formula from a newer app into an older one and it fails, the missing switch is the first thing to check.

Consultant notes

  • These, plus enhanced component properties, are what make it defensible to build a genuinely large canvas app. If a client asks why their previous canvas project became unmaintainable, this is a large part of the honest answer.
  • Both are GA now, so there's no preview caveat to attach to a delivery plan. That's a change from a year ago and worth saying out loud to clients who were told to avoid them.
  • Push UDTs hard on any integration work. Typed ParseJSON removes a category of runtime failures that used to surface as blank labels with no error.
  • Set the convention early that shared logic lives in App.Formulas and not in a component nobody remembers exists. The tooling doesn't enforce a choice, so you have to.

Worth revisiting when recursion or module-style organisation for App.Formulas ships.

Was this accurate?