Skip to content

Developers · Best Practices

Dynamic Cache

Last updated 2 November 2026

Dynamic cache works similarly to static cache. You can use it to cache the whole page, but the difference is that it triggers authorization, which also works for logged-in users. The cache will be invalidated whenever you change something on the page and deploy it. In reality, it's rarely possible to cache the whole page or layout (this is why is by default).

A dynamic cache is used when a page is often visited (for example, a homepage with products from the database, a landing page with recently registered users), and you want this page to be fast and protected against the vast amount of visitors flooding from a marketing campaign. Data cached on those pages usually do not need to be real-time because it is not critical. Regarding products on the homepage example: Last viewed products on the homepage, it is not vital for this list to be real-time; it can be cached for 60 seconds or even more to improve the site's performance.

Explanation

A dynamic cache is defined in page configuration.

---
dynamic_cache:
  expire:
  layout:
  key:
---

Details for each of the configuration options are displayed in the table below.

Properties Description Default

expire

Number of seconds since cache creation, after which it will not be taken into consideration when requested again.

If is set to 0 and is set, the cache will never expire by itself (updating the file would invalidate the cache, though).

If is blank and is 0, the page won't be cached.

If you update a page either by sync or deploy, it will invalidate the cache, no matter if the expiration time has passed or not.

none

layout

Make the layout part of the cached page.

false

key

Unique identifier for the page.

If you cache a page for 10 seconds and the is blank, the system will generate a cache for the whole URL. The system will not consider the cache if the user changes anything in the URL.

If the page content does not depend on arguments, it's best to restrict to (and/or etc.).

full page URL with query params.

For example https://example.com?my_arg=1

Example 1

app/views/pages/dynamic-cache.liquid

---
dynamic_cache:
  expire: 10
  layout: true
---
Session ID: {{ context.session.session_id }} <br>
Authenticity Token: {{ context.authenticity_token }} <br>
Random Seed: {{ 5 | random_string }}

Example 2

You can cache a page depending on the last update of multiple records to invalidate the cache only when needed. You might cache a page this way to refresh its content after you add new products to the store you manage.

app/views/pages/dynamic-records.liquid

---
dynamic_cache:
  layout: true
  key: >
    {%- assign tables = 'modules/n_plus_one/programmer,modules/n_plus_one/company' | split: ',' -%}
    {%- graphql result = 'records_updated_at', tables: tables -%}
    {%- assign record = result.records.results | first -%}
    {{ context.page.slug | append: record.updated_at }}
---
{% assign tables = 'modules/n_plus_one/programmer,modules/n_plus_one/company' | split: ',' %}
{% graphql result = 'get_records', tables: tables %}
{% assign records = result.records.results %}

This page cache will be invalidated when any of the `programmer` or `company` records changes or when this page is updated. Whichever comes first. <br>

Random string: {{ 18 | random_string }} <br>

<ul>
  {% for item in records %}
    <li>[{{ item.updated_at }}] {{ item.table }} - {{ item.properties.email }}</li>
  {% endfor %}
</ul>

Both queries take the table names in the variable, which the page builds with the filter.

app/graphql/get_records.graphql

query records($tables: [String!]) {
  records(
    per_page: 3
    sort: { updated_at: { order: DESC } }
    filter: { table: { value_in: $tables } }) {
    results {
      properties
      updated_at
      table
    }
  }
}

app/graphql/records_updated_at.graphql

query records_updated_at($tables: [String!]) {
  records(
    per_page: 1
    sort: { updated_at: { order: DESC } }
    filter: { table: { value_in: $tables } }
  ) {
    results {
      updated_at
    }
  }
}