Power Pages Liquid templating

How Liquid templates work in Power Pages — variables, tags, filters, rendering Dataverse data, and the design patterns for customer-facing portals.

Updated 2027-03-31

Power Pages portals — Microsoft's external-facing website platform on top of Dataverse — render content through the Liquid template language. Originally created by Shopify, Liquid is a logic-light templating language designed for safe content rendering. Understanding it is essential for building anything beyond the simplest Power Pages portal.

The Liquid concept. Liquid templates mix HTML with objects (data variables), tags (control flow), and filters (transformations). Templates compile and render server-side; the result is HTML sent to the user's browser.

Three types of Liquid elements.

  • Output (in {{ }}) — print a value.
  • Tags (in {% %}) — control flow (if, for, capture, etc.), but no output.
  • Filters (in | filter) — transform values during output.

Example:

{% if user.fullname %}
  <p>Welcome, {{ user.fullname | upcase }}!</p>
{% else %}
  <p>Welcome, guest.</p>
{% endif %}

The {% if %} and {% endif %} are tags; {{ user.fullname }} is an output; | upcase is a filter.

Power Pages-specific objects. The portal exposes specific objects:

  • user — the authenticated user (when signed in). Properties include fullname, email, id, roles.
  • page — the current page being rendered. Properties: title, summary, url.
  • entities — access to Dataverse entities. Used for querying records: {% entitylist logical_name:"contact" %}.
  • entityform — for forms tied to specific Dataverse forms.
  • weblinks — navigation menus configured in Power Pages.
  • request — current HTTP request context.
  • settings — site-level configuration.
  • now — current date/time.

These objects give templates access to the live data layer of the portal.

Querying Dataverse records.

{% fetchxml entities_query %}
<fetch>
  <entity name="opportunity">
    <attribute name="name" />
    <attribute name="estimatedvalue" />
    <filter>
      <condition attribute="ownerid" operator="eq" value="{{ user.id }}" />
    </filter>
  </entity>
</fetch>
{% endfetchxml %}

{% for opp in entities_query.results.entities %}
  <p>{{ opp.name }} — {{ opp.estimatedvalue | currency }}</p>
{% endfor %}

The {% fetchxml %} tag runs a FetchXML query; the result is available in subsequent template logic. Power Pages also supports the {% entityview %} tag for using saved Dataverse views and {% entitylist %} for configured lists.

Common filters.

  • upcase, downcase, capitalizecase manipulation.
  • date — format dates ({{ contact.createdon | date: "yyyy-MM-dd" }}).
  • currency — format money values.
  • escape — HTML-escape (default for user content; rarely turned off).
  • size — count of array or characters of string.
  • first and last — first / last element of an array.
  • limit — limit array to N elements.
  • truncate — shorten text.
  • replace — string replace.
  • url_encode — for building safe URLs.

Logic — if, unless, case.

{% if user.roles contains 'VIP' %}
  <p>VIP content</p>
{% elsif user.roles contains 'Member' %}
  <p>Member content</p>
{% else %}
  <p>Public content</p>
{% endif %}

{% case user.country %}
  {% when "Sweden" %}
    <p>Welkommen!</p>
  {% when "Germany" %}
    <p>Willkommen!</p>
  {% else %}
    <p>Welcome!</p>
{% endcase %}

Loops — for.

{% for opportunity in opportunities %}
  <p>{{ opportunity.name }}</p>
{% endfor %}

{% for product in products limit: 5 %}
  <p>{{ product.name }}</p>
{% endfor %}

Capture and variables. {% capture %} stores rendered output in a variable for later use:

{% capture greeting %}
  Hello, {{ user.fullname | default: "guest" }}
{% endcapture %}
<h1>{{ greeting }}</h1>

Includes. Reusable template fragments via {% include %}:

{% include 'header' %}
... main content ...
{% include 'footer' %}

Performance. Liquid is fast but complex queries inside loops can degrade:

  • Move queries outside loops where possible.
  • Use {% fetchxml %} with precise filters rather than fetching everything.
  • Cache repeated lookups in capture variables.

Security. Liquid is sandboxed — templates can't execute arbitrary code; they can only call defined functions and access defined data. This is the deliberate safety property — templates run as content, not as code.

User-supplied input rendered through Liquid is escaped by default (HTML-escaped), preventing XSS. Don't bypass escaping unless you know the source is trusted.

Common pitfalls.

  • Queries inside heavy loops — N+1 query pattern slows rendering.
  • Forgetting to escape — using | raw or similar to bypass escaping on user content is an XSS vulnerability.
  • Templates that mix too much logic — Liquid is for presentation; complex business logic belongs in Power Automate / plug-ins, not templates.
  • Unfamiliar filter / tag — Microsoft documents Power Pages-specific extensions; verify exists before using.

Operational reality. Liquid is straightforward once you've built a few templates. The Power Pages designer + Liquid combination produces effective portals without diving into full web development. For more complex needs (rich client interaction, custom UI), consider whether Power Pages is the right tool or if a custom-built solution makes more sense.

Related guides