---
title: Limit how many items a Liquid array fetches
description: >-
  A `for` loop's `limit` parameter reduces the database fetch for
  `collection.products` and `collections`, but not for other Liquid arrays. Use
  `paginate` for the arrays that need it.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/limit-product-queries-with-pagination
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/limit-product-queries-with-pagination.md
api_name: liquid
---

# Limit how many items a Liquid array fetches

Fetch only the items that you'll render. For `collection.products` and `collections`, a `for` loop's `limit` parameter is enough. Other Liquid arrays need the `paginate` tag.

***

## Why

Each product that a Liquid array loads carries database queries for variant data, images, pricing, and availability. Fetching 50 products to render 4 multiplies those queries, which increases TTFB and delays FCP and LCP.

How you avoid the extra fetch depends on the array.

***

## How

### `collection.products` and `collections`: `limit` is enough

Both of these arrays reduce the fetch to match a `for` loop's `limit`, so no `paginate` wrapper is needed:

```liquid
{%- comment -%} Fetches 4 products, not 50 {%- endcomment -%}
{% for product in collection.products limit: 4 %}
  {{ product.title }}
{% endfor %}
```

The optimization applies when the loop isn't already inside a `{% paginate %}` block and the limit is below the array's default page size, which is 50 for `collection.products` and 1,000 for `collections`. Without a `limit`, the loop fetches the full default page size.

**Caution:**

Don't reach for `{% paginate %}` to fix a one-off carousel or featured-products row. A `{% paginate %}` block responds to the `page` URL parameter, so a section that's wrapped in one renders different items, or none at all, on `?page=2`. Use `limit` for fixed-size lists and reserve `{% paginate %}` for lists that a customer actually pages through.

### Other arrays: use `paginate`

`blog.articles`, `search.results`, `product.variants`, `pages`, `customer.orders`, `customer.addresses`, and `article.comments` don't reduce their fetch in response to `limit`. For these, `limit` controls iterations only, and `{% paginate %}` controls the fetch:

```liquid
{%- comment -%} Fetches the default page size, then iterates 4 times {%- endcomment -%}
{% for article in blog.articles limit: 4 %}
  {{ article.title }}
{% endfor %}


{%- comment -%} Fetches 4 articles {%- endcomment -%}
{% paginate blog.articles by 4 %}
  {% for article in blog.articles limit: 4 %}
    {{ article.title }}
  {% endfor %}
{% endpaginate %}
```

Keep both `paginate by 4` and `limit: 4`. The `paginate` tag limits the database query, and `limit` caps the iterations.

***

## Examples

### Featured products

A fixed-size row of products needs `limit` only. Adding `{% paginate %}` here would couple the row to the `page` URL parameter:

```liquid
<div class="featured-products">
  {% for product in collections.featured.products limit: 4 %}
    <div class="product-card">
      {{ product.featured_image | image_url: width: 600 | image_tag: loading: 'lazy' }}
      <h3>{{ product.title }}</h3>
      <p>{{ product.price | money }}</p>
    </div>
  {% endfor %}
</div>
```

### Blog articles

`blog.articles` doesn't respond to `limit`, so this one needs the `paginate` wrapper:

```liquid
{% paginate blog.articles by 4 %}
  {% for article in blog.articles limit: 4 %}
    {{ article.title }}
  {% endfor %}
{% endpaginate %}
```

### Recommended limits by section type

| Section type | Recommended limit | Reasoning |
| - | - | - |
| Featured products | 4 to 6 | Above the fold, highly visible |
| Carousels (initial load) | 4 to 8 | Only show what's initially visible |
| Product recommendations | 2 to 4 | Most relevant only |
| Grid sections | 8 to 12 | Balance between content and load time |
| Paginated collections | 24 to 50 | Per-page limit with pagination controls |

***

## Testing

* Use the **Theme Inspector** to compare Liquid render time with different product limits.
* Measure TTFB in the [Chrome DevTools Network panel](https://developer.chrome.com/docs/devtools/network) with different query sizes.
* Check the `server-timing` header for database query counts.

***

## References

* [`paginate`](https://shopify.dev/docs/api/liquid/tags/paginate) tag
* [`for`](https://shopify.dev/docs/api/liquid/tags/for) tag
* [Dawn PR #3688](https://github.com/Shopify/dawn/pull/3688): pagination pattern applied to the Dawn theme
* [Avoid deeply nested Liquid loops](https://shopify.dev/docs/storefronts/themes/best-practices/performance/avoid-deeply-nested-liquid-loops)
* [Limit pagination depth](https://shopify.dev/docs/storefronts/themes/best-practices/performance/limit-pagination-depth)
* [Use the Section Rendering API](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-section-rendering-api)

***
