---
title: Use the new collections model
description: >-
  Learn how to use the new collections model capabilities in the GraphQL Admin
  API 2026-07.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/product-merchandising/products-and-collections/use-new-collections-model
  md: >-
    https://shopify.dev/docs/apps/build/product-merchandising/products-and-collections/use-new-collections-model.md
---

# Use the new collections model

The `2026-07` version of the GraphQL Admin API introduces a composable collections model. A collection is no longer a single custom or smart definition. It's a union of sources that can combine manual picks, automated conditions, sub-collections, and shareable app-owned sources in one collection.

This page explains how the model works and how to use its new capabilities: multi-value conditions, manual exclusions, sub-collections, variant-scoped sources, and shareable app-owned sources. If you're moving existing collection code to `2026-07`, start with the [migration guide](https://shopify.dev/docs/apps/build/product-merchandising/products-and-collections/migrate-to-flexible-collections).

***

## How the new model works

A collection is a union of sources. A collection has one or more sources, and its membership is the union of what each source resolves to. Each source contributes products through inclusions (conditions and explicit selections) and can remove them through exclusions, evaluated per source and reconciled into the collection's final membership.

A source is one of three types:

* A **conditions source** ([`CollectionConditionsSource`](https://shopify.dev/docs/api/admin-graphql/2026-07/objects/CollectionConditionsSource)) is conditions plus explicit product or variant selections. This is the evolution of smart-collection rules.
* A **sub-collection source** ([`CollectionSubCollectionsSource`](https://shopify.dev/docs/api/admin-graphql/2026-07/objects/CollectionSubCollectionsSource)) draws its membership from one or more other collections.
* A **shareable source** is a conditions source, often app-owned, linked in by reference and reused across many collections.

Because membership is a union, manual picks, automated conditions, and app-owned sources can coexist in one collection. In the legacy model a collection was either custom (you hand-pick every product) or smart (conditions, Shopify computes the membership); the new model combines these two approaches rather than forcing you to choose between them.

You define a collection's sources when you create it with [`collectionCreate`](https://shopify.dev/docs/api/admin-graphql/2026-07/mutations/collectionCreate), and change them afterward with [`collectionUpdate`](https://shopify.dev/docs/api/admin-graphql/2026-07/mutations/collectionUpdate). `CollectionUpdateInput` exposes `sourcesToCreate`, `sourcesToUpdate`, and `sourcesToDelete`, so you can change a single source without resubmitting the whole collection definition.

The following example creates one collection that blends all three source types: a conditions source (with a manual pick alongside its conditions), a sub-collection source, and a linked shareable source.

## Create a collection from multiple sources

```graphql
mutation {
  collectionCreate(collection: {
    title: "Summer Edit",
    sources: [
      {
        source: {
          title: "Summer Conditions",
          targetType: PRODUCTS,
          inclusion: {
            matchType: ALL,
            conditions: [{
              productTag: { relation: TAGGED_WITH, values: ["Summer"], matchType: ANY }
            }],
            selections: [{ productId: "gid://shopify/Product/1" }]
          }
        }
      },
      {
        subCollections: {
          title: "Featured",
          collectionIds: ["gid://shopify/Collection/10"]
        }
      },
      {
        shareableSource: { sourceId: "gid://shopify/CollectionConditionsSource/99" }
      }
    ]
  }) {
    collection {
      id
      title
      sources { __typename id title }
      productsCount { count precision }
    }
    userErrors { field message }
  }
}
```

***

## New capabilities

This new model introduces the following capabilities.

### Multi-value conditions

Some typed conditions now support lists of values. A single condition can match a list, like "tag is one of `shirt`, `pants`, or `shoes`", instead of needing a separate rule per value.

### Manual product exclusions

`CollectionConditionsSource.exclusion` accepts manual product selections (`selections`) the same way `inclusion` does, so you can drop specific products from a source's membership, like "everything tagged `vegan`, except these two products". Use `selections` for manual product exclusions, and use `conditions` for condition-based exclusions like collections (see [Exclude by collection](#exclude-by-collection)).

### Exclude by collection

A conditions-based source can exclude the membership of other collections with a `CollectionSourceExclusionConditionCollection`, up to 5 per collection. Collection condition exclusions can't currently be combined with any other exclusion condition type.

## Exclude by collection

```graphql
mutation {
  collectionUpdate(collection: {
    id: "gid://shopify/Collection/6",
    sourcesToCreate: [{
      source: {
        title: "Denim, except Outerwear",
        targetType: PRODUCTS,
        inclusion: {
          matchType: ANY,
          conditions: [{
            productTag: { relation: TAGGED_WITH, values: ["denim"], matchType: ANY }
          }]
        },
        exclusion: {
          matchType: ANY,
          conditions: [
            {
              collection: {
                values: ["gid://shopify/Collection/1", "gid://shopify/Collection/2"]
              }
            }
          ]
        }
      }
    }]
  }) {
    collection { id }
    userErrors { field message }
  }
}
```

### Sub-collections

A [`CollectionSubCollectionsSource`](https://shopify.dev/docs/api/admin-graphql/2026-07/objects/CollectionSubCollectionsSource) makes one collection inherit the membership of other collections through `collectionIds`. Sub-collection chains are restricted to a depth of one: a sub-collection target can't itself be a sub-collection. When an ineligible target is supplied, the mutation returns a `userErrors` entry.

## Add a sub-collection source

```graphql
mutation {
  collectionUpdate(collection: {
    id: "gid://shopify/Collection/3",
    sourcesToCreate: [{
      subCollections: {
        title: "Mirror of Featured",
        collectionIds: ["gid://shopify/Collection/2"]
      }
    }]
  }) {
    collection { id }
    userErrors { field message }
  }
}
```

### Variant-scoped sources

Set `targetType: VARIANTS` on a conditions-based source to evaluate conditions per variant rather than per product. Only the variants that satisfy the conditions are members of the collection: products with no matching variants don't appear at all, and products with some matching variants appear with only those variants.

Manual variant selection takes the same [`CollectionInclusionProductSelectionInput`](https://shopify.dev/docs/api/admin-graphql/2026-07/input-objects/CollectionInclusionProductSelectionInput) shape used everywhere else. Include both `productId` and `variantIds` when you manually select variants. Manually targeting a whole product isn't allowed on a variant-scoped source.

Storefront and Function consequences:

* Storefront filters and facets on a variant-scoped collection scope to included variants on collection pages.
* Swatches and selected variants on the storefront reflect only included variants.
* A Function input query for a variant-scoped collection must read from `ProductVariant.inCollections`, as covered in [Step 8 of the migration guide](https://shopify.dev/docs/apps/build/product-merchandising/products-and-collections/migrate-to-flexible-collections#step-8-move-function-input-queries-to-read-from-productvariant).

### Shareable, app-owned sources

Apps can author sources that aren't tied to a single collection through three new public mutations: [`collectionConditionsSourceCreate`](https://shopify.dev/docs/api/admin-graphql/2026-07/mutations/collectionConditionsSourceCreate), [`collectionConditionsSourceUpdate`](https://shopify.dev/docs/api/admin-graphql/2026-07/mutations/collectionConditionsSourceUpdate), and [`collectionConditionsSourceDelete`](https://shopify.dev/docs/api/admin-graphql/2026-07/mutations/collectionConditionsSourceDelete). The source returned by these mutations carries `shareable: true` and `app: <the calling app>`.

Link a shareable source into a collection through [`CollectionShareableSourceInput`](https://shopify.dev/docs/api/admin-graphql/2026-07/input-objects/CollectionShareableSourceInput) inside `sourcesToCreate` or `sources`. The same source can be linked into many collections at once. When an app updates the source, every collection that links it picks up the change automatically.

Apps can list their own sources through [`collectionConditionsSources`](https://shopify.dev/docs/api/admin-graphql/2026-07/queries/collectionConditionsSources), and merchants can discover which apps publish sources through [`collectionConditionsSourcesByApp`](https://shopify.dev/docs/api/admin-graphql/2026-07/queries/collectionConditionsSourcesByApp).

A shareable source exists independently of any collection. `collectionConditionsSourceCreate` returns a saved source that's linked to zero collections, so you can author a source, leave it unlinked, and attach it later. List your app's sources, including unlinked ones, with `collectionConditionsSources`.

This lifecycle applies only to app-owned shareable sources:

* App-owned shareable sources persist when unlinked from a collection, or when a collection is deleted. They're only removed when your app calls `collectionConditionsSourceDelete`. Deleting a source also unlinks it from every collection that currently uses it.
* Collection-scoped sources (the conditions you author directly on a collection) and sub-collection sources are non-shareable. They're tied to their collection and are deleted as soon as they no longer belong to one. Use a shareable source if you need a configuration that outlives any single collection.

***

## Collection webhooks

The collection webhook topics are unchanged in `2026-07`: [`collections/create`](https://shopify.dev/docs/api/webhooks?reference=toml#list-of-topics-collections/create), [`collections/update`](https://shopify.dev/docs/api/webhooks?reference=toml#list-of-topics-collections/update), and [`collections/delete`](https://shopify.dev/docs/api/webhooks?reference=toml#list-of-topics-collections/delete) keep firing, with the same `read_products` access scope. Publication changes continue to fire `collection_listings/{add,remove,update}` and `collection_publications/{create,update,delete}`. The new sources model doesn't add any webhook topics, and it doesn't add sources, exclusions, or sub-collections to the webhook payload. The payload keeps its existing, legacy JSON (or XML) shape. What changes is the `rules` field, described below.

The webhook payload still exposes the legacy `rules` (an array of `{ column, relation, condition }`) and `disjunctive` fields, but only when the collection can be faithfully represented through the legacy single-source, products-only shape. Shopify evaluates this per collection and constructs the payload as follows:

* **The collection stays legacy-expressible.** It has exactly one conditions-based source that targets `PRODUCTS`, uses only legacy-compatible attributes, applies a consistent `ALL`/`ANY` match type, and has no exclusions and no mix of manual selections with conditions. The payload includes `rules` (the source's conditions translated back to legacy rules) and `disjunctive`, exactly as a smart collection does today.
* **The collection uses any new feature.** It uses multiple sources, variant targeting, exclusions, a sub-collection source, a new condition type, a mix of manual selections and conditions, or an app-owned source. The payload omits `rules` and `disjunctive` entirely, and older API versions return `404 Not Found` for the collection.

A collection created with the new API therefore behaves the same as any other collection: whether `rules` appears in its webhook payload depends only on whether its sources stay within the legacy shape, not on which mutation created it.

To read a collection's full source configuration, query [`Collection.sources`](https://shopify.dev/docs/api/admin-graphql/2026-07/objects/Collection#field-Collection.fields.sources) as shown in [Step 2 of the migration guide](https://shopify.dev/docs/apps/build/product-merchandising/products-and-collections/migrate-to-flexible-collections#step-2-move-reads-from-ruleset-to-sources) rather than relying on the webhook payload.

***

## Limits

The new model applies per-shop and per-collection limits. Exceeding a limit returns a `userErrors` entry on the mutation rather than partially applying the change.

### Per shop

| Limit | Value | Notes |
| - | - | - |
| Collections | 100,000 | |
| Conditions-based collections | 5,000 | |
| Variant-level collections | 100 | Collections that use a variant-targeted source. |
| Collections with sub-collections | 50 | Collections that include a sub-collection source. |
| Collections with sub-collection exclusions | 5 | Collections that exclude members by referencing another collection. |

### Per collection

| Limit | Value | Notes |
| - | - | - |
| Sources | 10 | |
| Conditions | 60 | Total across the collection. Each value counts separately: `productTag` equal to `["spring", "summer"]` is 2 conditions. |
| Variants in a variant-level collection | 100,000 | Membership beyond the cap isn't stored. |
| Manual exclusions | 1,000 products | |
| Sub-collection inclusions | 10 | |
| Sub-collection exclusions | 5 | |

Sub-collection sources are limited to a nesting depth of one: a collection can pull members from another collection, but that collection can't itself pull from a further collection. This prevents circular references.

***

## Versioning and compatibility

* Apps on `2026-07` see all collections, including ones that use new features.
* Apps on `2026-04` or earlier continue to read and write legacy-shaped collections without change. They get `404 Not Found` for collections that use any new feature, including multiple sources, new condition types, sub-collection sources, and variant-targeted sources.
* The legacy mutations and fields, including [`collectionAddProducts`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/collectionAddProducts), [`collectionRemoveProducts`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/collectionRemoveProducts), [`collectionAddProductsV2`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/collectionAddProductsV2), `Collection.ruleSet`, `CollectionInput`, and [`collectionRulesConditions`](https://shopify.dev/docs/api/admin-graphql/latest/queries/collectionRulesConditions), are deprecated but remain available in `2026-07`.

**Info:**

Cache and replay carefully when bumping API versions. A collection that loads on `2026-07` might be invisible on `2026-04` if it uses any new feature, so a multi-version client needs to handle that case explicitly rather than treat it as a transient error.

***
