In short: A Liquid loop over a Shopify metaobject definition’s values stops after 50 entries; wrapping it in a paginate tag with a page size of up to 250 reaches more. In our test, a split array and a numeric range of 1,300 items were not capped.
How do you loop over more than 50 metaobject entries in Liquid?
Put the loop inside a paginate tag that paginates the same list, and set the page size to 250. These are the rules that held in our test, which used a theme app extension on a development store with the 2026-10 API:
- A plain loop over a definition's
valuesstops at 50 entries. Shopify documents this limit[1]. paginateraises the ceiling to the page size. The tag accepts a page size from 1 to 250[2], andmetaobject_is one of the arrays it can paginate[2][1]. Insidedefinition. values {% paginate ..., the same loop reached all 250 entries we seeded. Shopify documents the ceiling of 250, but we did not see it enforced for metaobject values: with 251 entries, page sizes of 251 and 1,000 both put all 251 on one page. Treat 250 as the documented limit, not as one we measured.by 250 %} - Paginate the list you loop over. The tag takes the array, so write
defn.valuesin both places, withdefnassigned once. - More than 250 entries means a second page.
paginate.pagesreports the total number of pages[3], and you decide what to do with the rest: show page links, or narrow the list before it grows that far. Build page addresses frompaginate.page_param[3] or from the next-page link, because the query parameter is not always calledpage. To load the next page without a reload, see our guide to load more and infinite scroll with the Liquid partial tag, which is a developer preview. - Looking entries up one handle at a time is not a way round. Shopify allows 20 unique handles per page that way, and pagination cannot be used with it[1].
A loop that stops at its cap can look like one that finished, so the block below counts the entries the loop actually reaches and prints that number next to the count Shopify reports.
This block only reads data and writes nothing, but add it on a development store or an unpublished copy of a theme first, never on the live theme, and remove it afterwards. Take a backup of the theme before editing it. You use this information at your own risk, and iLogr accepts no responsibility for any loss or damage.
{%- assign defn = metaobjects['$app:entry'] -%}
{%- assign seen = 0 -%}
{%- paginate defn.values by 250 -%}
{%- for item in defn.values -%}
{%- assign seen = seen | plus: 1 -%}
{%- endfor -%}
<pre>
values_count: {{ defn.values_count | json }}
rendered: {{ seen }}
pages: {{ paginate.pages }}
</pre>
{%- endpaginate -%}
{% schema %}
{
"name": "Entry count probe",
"target": "section",
"settings": []
}
{% endschema %}
Save it as a block file in the extension and replace entry with your type. Shopify documents the same values property for any definition, and its own example loops over metaobjects.[1]. For a merchant-owned type, replace the first line with {%- assign defn = metaobjects. and leave the rest unchanged. We ran the probe against both an app-owned type in a theme app extension and a merchant-owned type in a theme section, and the numbers matched. Add the block to a product template and load the page. Read the three numbers together: if pages is 1 and rendered is lower than values_count, entries were left out of the loop, and drafts are one documented reason to rule out first[1]; if pages is above 1, the list spans several pages and rendered shows only the current one. Our setup is described in the field note below, and access to app-owned types is covered in our article on reading them from a theme app extension.
What did a test at 49, 50, 51 and 250 entries show? (field note)
Field note: a test on a development store. In a test on a development store with API version 2026-10, we raised the number of entries in an app-owned metaobject definition in steps and rendered a theme app block that looped over its values twice: once on its own and once inside paginate ... by 250. The extra entries were plain filler records. Before each read we waited until the storefront reported the new count.
| Entries | Count reported | Plain loop reached | Loop inside paginate reached | Pages |
|---|---|---|---|---|
| 49 | 49 | 49 | 49 | 1 |
| 50 | 50 | 50 | 50 | 1 |
| 51 | 51 | 50 | 51 | 1 |
| 249 | 249 | 50 | 249 | 1 |
| 250 | 250 | 50 | 250 | 1 |
| 251 | 251 | 50 | 250 | 2 |

Three things stand out. The plain loop reached every entry up to 50 and stayed at 50 above that. The paginated loop followed the count to 250 and then stopped at 250, the page size, with a second page. And the reported count matched the seeded count in every row, which is what makes the other columns readable.
Two smaller results from the same page. With one page of entries, adding ?page=2 or ?page=3 to the address changed nothing: the current page stayed 1 and all 250 entries rendered. That was because page is not the parameter these lists use. It is a keyed name, the word page followed by an underscore and eight characters, and paginate.page_param reports it[3]. In a clean re-test with the keyed name, a value of 2 or 3 moved the current page to 2 or 3 and rendered no entries at 250 entries, and at 251 entries page 2 rendered one entry, the last. And two paginated blocks on one product page each reached all 250 entries.
Do arrays and ranges stop at 50 too?
Not in our test, and that matters for how you test a fix. On the same page, a loop over a string split into 1,300 parts reached all 1,300, and so did a loop over the numeric range (1..1300). Neither stopped at 50, and neither needed paginate.
Shopify's reference pages state the limit more broadly. The for page says "You can do a maximum of 50 iterations with a for loop"[4], and the paginate page says for loops "are limited to 50 iterations per page"[2]. Those sentences describe the documented rule. What we measured was narrower: the cap bit on the unpaginated loop over a definition's values, and it did not bite on the two plain constructs we tried. We did not test other paginatable lists such as collection products, loops over reference-list fields of more than 50 items, or the limit and offset parameters.
The practical lesson is about test data, not about the platform. A generated range or split string can miss the metaobject limit: both reached 1,300 items in our test while the plain metaobject loop stopped at 50. Seed real entries, and seed them on both sides of each boundary: 51 for the plain cap, and 251 if you use a page size of 250. Then read the count and the rendered number side by side, as the probe does.
How can you tell that a loop was cut short?
You cannot tell from the visible entries alone: a block that lists 50 of 70 entries can look like one that lists 50 of 50. Three signals help:
- Compare counts on known fixtures.
values_countis the number of entries in the definition[1]. When the list fits on one page and your loop's counter is lower, entries were left out. On a multi-page list the counter covers one page, and for a publishable definition drafts are skipped in loops[1]; we did not test whether the count includes them. - Check
paginate.pages. A value above 1 means the list spans several pages[3]. Compare it withpaginate.current_page: on the page wherecurrent_pageis belowpages, more entries follow. This does not depend on the count at all. - Watch the number that gets close to 50. A feature that works with 12 entries and quietly drops the 51st is the typical failure, because every test before the 51st passes.
Code that builds on the loop inherits the gap. A lookup table made from the first 50 entries finds nothing for entry 70, which looks like a data problem. Check the count before you check the data.
Does pagination have limits of its own?
Yes. Shopify's pagination stops at the 25,000th item, and counts are accurate only up to 25,000, after which they return 25,001[2][5]. A list that large needs narrowing before it is paged.
Shopify also says that pairing paginate with a matching limit on the loop can reduce the data fetched, using collection products as its example[2]. Our table used a page size of 250 only; in the re-test, 251 and 1,000 were also accepted for metaobject values. We did not test whether a matching limit saves any data, so treat that saving as documented behaviour, not ours.
Why re-test when the platform version changes?
The cap sits in the platform, not in your code, so it can move with a Shopify release. Our table comes from API version 2026-10, and a clean re-run on a theme app extension and on a theme section gave the same numbers. A later check of the production version of the block, with 104 entries behind a paginated loop, still produced the expected output, but it did not repeat the full table. When you move to a new API version or a new theme, run the probe again with one count below and one above each boundary you rely on.
Can you reproduce these numbers yourself?
Yes. A small open repository seeds 49, 50, 51, 249, 250 and 251 entries into a merchant-owned definition and into an app-owned one, reads the probe after each step, and checks ?page=N, the keyed page parameter and page sizes of 251 and 1,000[6]. It was run twice from scratch with Shopify CLI 4.9.4, API version 2026-10 and Horizon 4.3.0, and a store with the Liquid July 2026 preview gave the same numbers. The storefront can report a new count up to about two minutes after seeding, so the scripts wait for it before they read.
The repository creates and deletes test data and a theme copy. Run it only on a development store you can throw away, never on a live store or a live theme, and read every script first. You use it at your own risk, and iLogr accepts no responsibility for any loss or damage.
References
Numbers in square brackets in the text link to these sources.
- Shopify.dev, Liquid objects:
metaobject_definition(opens in a new tab).Used for: the 50-entry loop limit, the 20-handle limit and the entry count property. - Shopify.dev, Liquid tags:
paginate(opens in a new tab).Used for: the page size range of 1 to 250 and the 25,000-item pagination limit. - Shopify.dev, Liquid objects:
paginate(opens in a new tab).Used for: the total pages and current page properties. - Shopify.dev, Liquid tags:
for(opens in a new tab).Used for: the documented 50-iteration limit for loops. - Shopify.dev, "Platform performance best practices" (pagination limits) (opens in a new tab).Used for: the 25,000 pagination limit and how counts behave above it.
- GitHub, iLogr, liquid-metaobject-loop-limit-repro.Used for: the probe, the seed and read scripts, the raw results and the tested versions.