There is no Liquid object for it yet.
I set the same thing up on a test store and checked every route.
What Liquid returns on a collection built from Collection sources:
{{ collection | json }}
{"id":359138394289,"handle":"furnishing","updated_at":"...","published_at":"...","sort_order":"most-relevant","template_suffix":null,"published_scope":"global","title":"Furnishing","body_html":null}
collection.sources, collection.sub_collections, collection.children all return nothing.
collection.metafields.shopify is empty.
- The Storefront API
Collection object has no sources field either.
- Admin GraphQL 2026-07 is the only place the list exists:
collection.sources then ... on CollectionSubCollectionsSource { collections }.
So nothing on the storefront can read it today.
Deriving it by looping collection.products and reading product.collections looks tempting but is not safe.
On my test it returned the 3 real sub-collections plus 2 unrelated ones, because it picks up every collection those products happen to sit in.
What works today : one list-of-collections metafield.
- Settings > Custom data > Collections > Add definition. Name it “Sub collections”, set the type to List of collections, leave Storefront API access on.
- Open the parent collection > Metafields, and pick the same sub-collections.
- Online Store > Themes > Customize, open your Collection template, then Add section > Custom Liquid.
- Paste this in the Custom liquid box and Save.
{%- assign subs = collection.metafields.custom.sub_collections.value -%}
{%- if subs != blank -%}
<div class="subcol-grid">
{%- for sub in subs -%}
<a class="subcol-card" href="{{ sub.url }}">
<span class="subcol-card__img">
{%- if sub.featured_image -%}
<img src="{{ sub.featured_image | image_url: width: 600 }}" alt="{{ sub.title | escape }}" width="600" height="600" loading="lazy">
{%- endif -%}
</span>
<span class="subcol-card__title">{{ sub.title }}</span>
<span class="subcol-card__count">{{ sub.all_products_count }} products</span>
</a>
{%- endfor -%}
</div>
<style>
.subcol-grid{display:grid;gap:1.6rem;grid-template-columns:repeat(2,1fr);max-width:var(--page-width,120rem);margin:0 auto;padding:0 1.5rem}
@media (min-width:750px){.subcol-grid{grid-template-columns:repeat(4,1fr);padding:0 5rem}}
.subcol-card{display:block;text-decoration:none;color:inherit}
.subcol-card__img{display:block;aspect-ratio:1/1;overflow:hidden;border-radius:.8rem;background:rgba(var(--color-foreground),.05)}
.subcol-card__img img{width:100%;height:100%;object-fit:cover;display:block}
.subcol-card__title{display:block;margin-top:.8rem;font-weight:600}
.subcol-card__count{display:block;font-size:1.3rem;opacity:.7}
</style>
{%- endif -%}
- The cards render above the product grid and each one links to that collection.
To stop the client filling it in twice, mirror the native sources into that metafield from your app. Read them with:
{
collection(id: "gid://shopify/Collection/1234567890") {
sources {
... on CollectionSubCollectionsSource {
collections { id title handle }
}
}
}
}
Then write the same ids back with metafieldsSet on the collections/update webhook. Your client only ever touches the native Collection card, and the theme reads the metafield.
Notes: change repeat(4,1fr) for the number of columns, and max-width if your theme is not 1200px wide.
Available apps: Breadcrumbs & Categories, Collection Tree: Discover, Subcollections Tree.
Regards,
Ploqo