Implement categories on the storefront
Use the following API operations to manage categories for Commerce projects that use the Merchandising Services composable catalog data model:
Create category data using the
categoriesoperations available in the Data Ingestion REST API, and using theproductsoperations to manage product category assignments.Retrieve category navigation and hierarchy data using the
navigationandcategoryTreequeries available in the Merchandising Services GraphQL API.Retrieve category context for products — such as breadcrumbs — using the
categoriesfield on product queries in the Merchandising Services GraphQL API.
For Commerce sites with an Adobe Commerce as a Cloud Service or an Adobe Commerce on Cloud infrastructure or on-premises backend, manage categories configuration from the Commerce Amin, and use the categories query available in the Catalog Service GraphQL API to manage categories.
Category types
The navigation query, categoryTree query, and categories field on product queries each return a different category type, optimized for its specific use case. All three types implement the CategoryViewV2 interface, which defines the two required fields shared by every category: slug and name. For complete field details, see CategoryViewV2 in the Merchandising Services GraphQL API reference.
- CategoryNavigationView — For menu rendering and navigation
- CategoryProductView — For category data returned with product queries
- CategoryTreeView — For hierarchical category management and rich category pages
CategoryNavigationView type
The CategoryNavigationView type implements CategoryViewV2 and provides category data optimized for storefront navigation. It contains:
- name and slug — Category identity
- children — Nested subcategories for building the full menu hierarchy in a single query
Use this type to render top menus, dropdowns, and mobile navigation.
Type definition
Copied to your clipboardtype CategoryNavigationView implements CategoryViewV2 {slug: String!name: String!children: [CategoryNavigationView]}
For complete field details, see [CategoryNavigationView](https://developer.adobe.com/commerce/webapi/graphql/merchandising/#definition-CategoryNavigationView) in the Merchandising Services GraphQL API reference.
See the Navigation query examples section for example queries and responses using this type.
CategoryProductView type
The CategoryProductView type implements CategoryViewV2 and provides category data within product query responses. Each product's categories field returns a list of CategoryProductView objects containing:
- name and slug — Category identity
- level — Position in the hierarchy
- parents — Full chain of ancestor categories
Use this type to render breadcrumbs, filter by category, or display category context on product detail pages.
Type definition
Copied to your clipboardtype CategoryProductView implements CategoryViewV2 {name: String!slug: String!level: Int!parents: [CategoryProductView!]}
The parents field is self-referencing—each parent entry is itself a CategoryProductView with its own name, slug, level, and parents. This allows you to reconstruct the full breadcrumb path for any category a product belongs to.
For complete field details, see CategoryProductView in the Merchandising Services GraphQL API reference.
See the Products query with categories examples section for example queries and responses using this type.
CategoryTreeView type
The CategoryTreeView type implements CategoryViewV2 and provides the richest category data. It contains:
- name and slug — Category identity
- level and parentSlug / childrenSlugs — Hierarchy and relationships
- description — Category descriptive content
- metaTags — SEO metadata (title, description, keywords)
- images — Category images
Use this type for rich category landing pages, SEO-driven content, and CMS administration.
Type definition
Copied to your clipboardtype CategoryTreeView implements CategoryViewV2 {slug: String!name: String!level: IntparentSlug: StringchildrenSlugs: [String]description: StringmetaTags: CategoryMetaTagsimages: [CategoryImage]}type CategoryMetaTags {title: Stringdescription: Stringkeywords: [String]}type CategoryImage {url: String!label: Stringroles: [String]customRoles: [String]}
For complete field details, including the CategoryMetaTags and CategoryImage types, see CategoryTreeView in the Merchandising Services GraphQL API reference.
See the CategoryTree query examples section for example queries and responses using this type.
Limitations and considerations
Choose the right query for the use case
- Use the
navigationquery for storefront menus. It is heavily cached, limited to four levels, and returns only the lightweight fields needed for rendering. - Use the
categoryTreequery when you need full hierarchy metadata, descriptions, images, or SEO fields. - Use the
categoriesfield on product queries only when category context (such as breadcrumbs) is needed on a product page. Omit it when it is not needed to avoid unnecessary overhead.
Navigation query depth limit
The navigation query returns a maximum of four levels of nested categories. Nesting children beyond four levels in your query returns no additional data. Design your category hierarchy and query depth accordingly.
categoryTree discovery-first behavior
When slugs is omitted from a categoryTree query, the depth parameter is ignored and only root-level (level 1) categories are returned. This is by design — the query uses a discovery-first pattern that lets clients find category tree entry points before fetching subtrees. To retrieve descendants, always pass slugs along with the desired depth.
Optional fields add overhead
The description, metaTags, and images fields on categoryTree are optional. Exclude them when building navigation or hierarchy views that do not need descriptive content or SEO metadata.
Limit categoryTree depth
Pass the depth parameter to categoryTree to avoid fetching deeper levels than you need.
Target specific subtrees
Pass the slugs parameter to categoryTree to fetch only the branches you need rather than the entire tree.
Navigation query examples
The navigation query signature:
Copied to your clipboardtype Query {navigation(family: String!): [CategoryNavigationView]}
The family parameter is required and specifies which category family to retrieve. The query returns the full hierarchy for that family in a single request.
Retrieve basic top menu navigation
Copied to your clipboardquery GetTopMenuNavigation {navigation(family: "top-menu") {slugnamechildren {slugnamechildren {slugname}}}}
Copied to your clipboard{"data": {"navigation": [{"slug": "men","name": "Men clothing","children": []}]}}
The response returns a single root node with no nested children:
Copied to your clipboardMen clothing└── (no children)
Retrieve multi-level menu navigation
Copied to your clipboardquery GetFullMenuNavigation {navigation(family: "menu") {slugnamechildren {slugnamechildren {slugnamechildren {slugname}}}}}
Copied to your clipboard{"data": {"navigation": [{"slug": "men","name": "Men clothing","children": [{"slug": "men/tops","name": "Men tops","children": [{"slug": "men/tops/jackets","name": "Jackets","children": []}]}]}]}}
The response returns a three-level nested hierarchy:
Copied to your clipboardMen clothing└── Men tops└── Jackets
Products query with categories examples
Copied to your clipboardtype ProductView {categories(family: String): [CategoryProductView]}
The categories field is available on product types such as ProductView. Use the optional family parameter to return only categories from a specific category family. When omitted, categories from all families are returned.
Retrieve product categories with breadcrumb ancestors
Copied to your clipboardquery {products(skus: ["shorts-red-m"]) {nameskucategories(family: "clothing") {namesluglevelparents {namesluglevel}}}}
Copied to your clipboard{"data": {"products": [{"name": "Red Shorts (M)","sku": "shorts-red-m","categories": [{"name": "Shorts","slug": "men/clothes/shorts","level": 3,"parents": [{"name": "Men","slug": "men","level": 1},{"name": "Clothes","slug": "men/clothes","level": 2}]}]}]}}
The parents array provides the full ancestor chain, which you can use to render a breadcrumb path:
Copied to your clipboardMen (level 1) → Clothes (level 2) → Shorts (level 3)└── product: Red Shorts (M)
Filter product categories by family
A product can belong to categories in multiple families. Use the family parameter to return only categories from a specific family. In this example, the product belongs to categories in both the "clothing" and "seasonal" families, but the query filters for "seasonal" only.
Copied to your clipboardquery {products(skus: ["shorts-red-m"]) {nameskucategories(family: "seasonal") {namesluglevelparents {namesluglevel}}}}
Copied to your clipboard{"data": {"products": [{"name": "Red Shorts (M)","sku": "shorts-red-m","categories": [{"name": "Summer Essentials","slug": "summer/essentials","level": 2,"parents": [{"name": "Summer","slug": "summer","level": 1}]}]}]}}
Without the family filter, the response would include categories from all families the product belongs to—for example, both "Shorts" from the "clothing" family and "Summer Essentials" from the "seasonal" family. The family parameter narrows the result to a single family, which is useful when rendering context-specific navigation or breadcrumbs.
CategoryTree query examples
The categoryTree query signature:
Copied to your clipboardtype Query {categoryTree(family: String!, slugs: [String!], depth: Int): [CategoryTreeView]}
Retrieve root-level categories
When called without slugs, the query returns only root-level categories. See categoryTree discovery-first behavior for details.
Copied to your clipboardquery GetRootCategories {categoryTree(family: "main-catalog") {slugnamelevelparentSlugchildrenSlugs}}
Copied to your clipboard{"data": {"categoryTree": [{"slug": "men","name": "Men's Category","level": 1,"parentSlug": "","childrenSlugs": ["men/clothing"]},{"slug": "women","name": "Women's Category","level": 1,"parentSlug": "","childrenSlugs": ["women/clothing"]}]}}
The flat list represents the root-level categories and their immediate children.
Copied to your clipboardMen's Category (level 1)└── Men's Clothing (level 2)Women's Category (level 1)└── Women's Clothing (level 2)
Retrieve specific category subtree
Copied to your clipboardquery GetSpecificCategorySubtree {categoryTree(family: "main-catalog"slugs: ["men/clothing", "women/clothing"]depth: 2) {slugnamelevelparentSlugchildrenSlugs}}
Copied to your clipboard{"data": {"categoryTree": [{"slug": "men/clothing","name": "Men's Clothing","level": 2,"parentSlug": "men","childrenSlugs": ["men/clothing/tops", "men/clothing/bottoms"]},{"slug": "men/clothing/tops","name": "Men's Tops","level": 3,"parentSlug": "men/clothing","childrenSlugs": []},{"slug": "men/clothing/bottoms","name": "Men's Bottoms","level": 3,"parentSlug": "men/clothing","childrenSlugs": []},{"slug": "women/clothing","name": "Women's Clothing","level": 2,"parentSlug": "women","childrenSlugs": ["women/clothing/tops", "women/clothing/bottoms"]},{"slug": "women/clothing/tops","name": "Women's Tops","level": 3,"parentSlug": "women/clothing","childrenSlugs": []},{"slug": "women/clothing/bottoms","name": "Women's Bottoms","level": 3,"parentSlug": "women/clothing","childrenSlugs": []}]}}
The depth parameter counts levels relative to the specified starting slugs, while the level field reflects each category's absolute position in the hierarchy based on its slug path.
Copied to your clipboardMen's Clothing (level 2) Women's Clothing (level 2)├── Men's Tops (level 3) ├── Women's Tops (level 3)└── Men's Bottoms (level 3) └── Women's Bottoms (level 3)
Retrieve category details with metadata and images
Use the description, metaTags, and images fields to build rich category landing pages that include SEO metadata and visual content. This is especially useful when rendering a category page that needs a hero image, descriptive copy, and proper <meta> tags for search engines.
Copied to your clipboardquery CategoryTree {categoryTree(slugs: ["men/clothes/shorts"], family: "clothing") {slugnamelevelparentSlugchildrenSlugsdescriptionmetaTags {titledescriptionkeywords}images {urllabelrolescustomRoles}}}
Copied to your clipboard{"data": {"categoryTree": [{"slug": "men/clothes/shorts","name": "Shorts","level": 3,"parentSlug": "men/clothes","childrenSlugs": [],"description": "Browse our full range of men's shorts, from casual to athletic styles.","metaTags": {"title": "Men's Shorts","description": "Shop men's shorts for every occasion","keywords": ["shorts","men"]},"images": [{"url": "https://example.com/images/shorts.jpg","label": "Men's shorts collection","roles": ["BASE","THUMBNAIL"],"customRoles": ["special-role"]}]}]}}
Query quick reference
| Use case | Query | Type |
|---|---|---|
Storefront menus, dropdowns, mobile navigation | navigation | CategoryNavigationView |
Category landing pages with SEO metadata and images | categoryTree | CategoryTreeView |
Breadcrumbs and category context on product pages | products (categories field) | CategoryProductView |
Category hierarchy management and CMS administration | categoryTree | CategoryTreeView |
