Taxonomy, tags, and classification systems
Taxonomy, tags, and classification systems
TL;DR
- Contentstack taxonomies provide governed, hierarchical classification with cross-content-type querying -- use them for navigation and filtering.
- Tags are freeform and zero-setup but drift into inconsistency; reserve them for informal, internal classification.
- Reference-based categorization is best when categories are rich content entities with their own pages and metadata.
- Layer all three mechanisms by purpose: taxonomies for governed facets, tags for ad-hoc labels, references for content-rich categories.
Classification determines how content is found, filtered, and surfaced. Contentstack provides three distinct mechanisms for classifying content: the Taxonomy feature, simple tag fields, and reference-based categorization. Each works differently at the data level, the query level, and the editorial level. Choosing the wrong one creates either rigid classification that editors cannot maintain or loose classification that developers cannot query reliably.
This lesson covers how Contentstack's Taxonomy feature works, how it differs from tags and references, and how to build filtered views and faceted navigation using taxonomies. The running example is Veda: The Revival Collection, a jewelry e-commerce site with products classified by product line (Digital Dawn, Urban Armor, etc.) and category (Earrings, Necklaces, Bracelets, Rings).
Three classification mechanisms
Before diving into taxonomies, it helps to see the full landscape:
Common pitfall: Using freeform tags for user-facing navigation or filtering leads to inconsistent classification -- after six months you end up with "AI", "A.I.", "ai", and "artificial-intelligence" all meaning the same thing, and queries miss content.
Tags are freeform string arrays attached to entries. They require no schema setup. Editors type any string they want. Tags are easy to add but hard to govern: nothing prevents "Technology", "technology", "tech", and "Tech" from coexisting as four separate tags that should be one.
Reference-based categorization uses a separate content type (for example, category) and reference fields on content entries. This gives categories their own entries with structured fields, editorial lifecycle, and API presence. However, categories are tied to a specific content type through reference fields, and querying across content types by category requires multiple API calls.
Taxonomies are a dedicated Contentstack feature designed specifically for classification. Taxonomies are defined centrally in the Taxonomy section of the stack, associated with content types at the schema level, and queryable across content types through a unified API syntax. They are the platform's purpose-built classification system.
How Contentstack taxonomies work
Creating taxonomies
Taxonomies are managed in the Contentstack UI under Taxonomy in the left navigation. Each taxonomy has a UID and a display name. Within a taxonomy, you define terms organized in a hierarchy.
For Veda, you would create taxonomies for classification beyond the core product_line and category references:
Taxonomy: product_line (for cross-content-type classification)
- Digital Dawn
- Urban Armor
- Charmed Revival
- Elegant Rebellion
Taxonomy: category
- Earrings
- Necklaces
- Bracelets
- Rings
Each term has its own UID (for example, digital_dawn, earrings). Terms can be nested to create hierarchical classification trees without the reference-depth problems described in lesson 2.2.2.
Associating taxonomies with content types
Once taxonomies exist, you associate them with content types. In the content type builder, the taxonomy field connects a content type to one or more taxonomies. Editors can then assign taxonomy terms to entries when creating or editing content.
For Veda, you would add taxonomy fields to the product content type:
- product content type: associated with product_line and category taxonomies
This means the Matrix Link Bracelet could be classified as:
- Product Line: digital_dawn
- Category: bracelets
How taxonomy data appears in entries
When an entry has taxonomy terms assigned, those terms are stored as part of the entry metadata. The API response includes taxonomy information that can be used for filtering and display:
{
"entry": {
"title": "Matrix Link Bracelet",
"uid": "blt_matrix_link_001",
"_content_type_uid": "product",
"taxonomies": [
{
"taxonomy_uid": "product_line",
"mandatory": false,
"non_localizable": false,
"term_uid": "digital_dawn"
},
{
"taxonomy_uid": "category",
"mandatory": false,
"non_localizable": false,
"term_uid": "bracelets"
}
]
}
}In practice, Delivery API responses often include additional metadata alongside taxonomy assignments. The important Veda-specific point is that each taxonomy item is not just a term UID; it also carries taxonomy-level attributes such as mandatory and non_localizable.
Querying by taxonomy
The primary advantage of taxonomies over tags and references is the query model. Contentstack provides a dedicated query syntax for filtering entries by taxonomy terms.
Basic taxonomy query
To find all entries classified under a specific taxonomy term, use the taxonomy query syntax in the query parameter:
GET /v3/content_types/product/entries
?query={"taxonomies.product_line":{"$in":["digital_dawn"]}}
&environment=productionThis returns all products tagged with the digital_dawn product line term. The $in operator accepts an array, so you can query for multiple terms:
GET /v3/content_types/product/entries
?query={"taxonomies.category":{"$in":["earrings","bracelets"]}}
&environment=productionCombining taxonomy queries
To filter by multiple taxonomies simultaneously (AND logic), combine taxonomy conditions in the query:
GET /v3/content_types/product/entries
?query={
"taxonomies.product_line":{"$in":["digital_dawn"]},
"taxonomies.category":{"$in":["earrings"]}
}
&environment=productionThis returns products classified under the digital_dawn product line AND the earrings category. For Veda, this query powers the "Digital Dawn earrings" filtered view.
Cross-content-type taxonomy queries
One of the most powerful aspects of taxonomies is querying across content types. The Taxonomy API allows you to find all entries (regardless of content type) that match specific taxonomy terms:
GET /v3/taxonomies/product_line/terms/digital_dawn/entries ?environment=production
This returns products, pages, and product lines that are all classified under digital_dawn. With reference-based categorization, you would need separate queries for each content type. Taxonomies unify this into a single query path.
The Taxonomy API endpoints
Contentstack provides dedicated API endpoints for working with taxonomies:
List all taxonomies in a stack:
GET /v3/taxonomies
Get a specific taxonomy with its terms:
GET /v3/taxonomies/{taxonomy_uid}List terms within a taxonomy:
GET /v3/taxonomies/{taxonomy_uid}/termsGet entries associated with a specific term:
GET /v3/taxonomies/{taxonomy_uid}/terms/{term_uid}/entriesThese endpoints let you build dynamic classification UIs: render taxonomy trees for navigation, show term counts, and build drill-down interfaces.
Taxonomy vs tags vs references: decision framework
Use taxonomies when
- Classification needs to be consistent and governed across the organization
- You need to query across multiple content types by the same classification
- The classification has a hierarchical structure (topics with subtopics, regions with countries)
- You need to build faceted navigation or filtered views in your frontend
- Editors should pick from predefined controlled vocabularies, not freeform text
Use tags when
- Classification is informal and editorial (editors tagging content with trending topics)
- Exact consistency is not critical for downstream queries
- You need a lightweight, no-setup classification for simple use cases
- Tags are used primarily for internal organization, not for powering structured navigation
Use reference-based categorization when
- Categories have rich metadata beyond a name (description, icon, featured image, SEO fields)
- Categories need their own editorial lifecycle with workflow and publishing states
- The category itself is a content entity that is rendered (a category landing page with its own layout)
- You only need categorization within one content type, not across types
Comparison table
| Dimension | Taxonomy | Tags | Reference-based |
| Governance | Controlled vocabulary | Freeform | Structured entries |
| Hierarchy | Built-in term trees | Flat | Manual via self-reference |
| Cross-type queries | Native support | Manual aggregation | Separate queries per type |
| Setup cost | Moderate (taxonomy admin) | Zero | High (content type + entries) |
| Rich metadata on categories | No (terms are lightweight) | No | Yes (full entry fields) |
| Editorial UX | Term picker | Text input | Entry reference picker |
| Query syntax | taxonomies.uid queries | tags array queries | include[] resolution |
Worked example: media company classification
The media company publishes three content types across two classification dimensions. Here is how the full classification system works end to end.
Content model setup
Each content type includes taxonomy associations:
article ├── title (single line) ├── slug (single line) ├── body (JSON RTE) ├── author (reference → author) ├── featured_image (file) ├── topic (taxonomy → topic) └── region (taxonomy → region) video ├── title (single line) ├── slug (single line) ├── video_url (single line) ├── duration (number) ├── transcript (JSON RTE) ├── topic (taxonomy → topic) └── region (taxonomy → region) podcast ├── title (single line) ├── slug (single line) ├── audio_file (file) ├── episode_number (number) ├── show_notes (JSON RTE) ├── topic (taxonomy → topic) └── region (taxonomy → region)
Building a topic hub page
A "Technology" topic hub page displays all content (articles, videos, podcasts) classified under technology, regardless of format. Without taxonomies, you would need three separate API calls and client-side merging. With taxonomies:
GET /v3/taxonomies/topic/terms/technology/entries ?environment=production &limit=20 &include_count=true
This single query returns a mixed list of articles, videos, and podcasts. Your frontend renders each entry based on its _content_type_uid:
function TopicHub({ entries }: { entries: any[] }) {
return (
<div classname="topic-hub">
{entries.map((entry) => {
switch (entry._content_type_uid) {
case "article":
return <articlecard key="{entry.uid}" {...entry}="">;
case "video":
return <videocard key="{entry.uid}" {...entry}="">;
case "podcast":
return <podcastcard key="{entry.uid}" {...entry}="">;
default:
return null;
}
})}
</podcastcard></videocard></articlecard></div>
);
}Building faceted navigation
Faceted navigation lets users narrow results by combining taxonomy filters. A sidebar on the topic hub page might show:
- Format: Articles (24), Videos (12), Podcasts (8)
- Region: APAC (15), EMEA (18), Americas (11)
Each facet combination maps to a taxonomy query:
// Technology articles in EMEA
GET /v3/content_types/article/entries
?query={
"taxonomies.topic":{"$in":["technology"]},
"taxonomies.region":{"$in":["emea"]}
}
&environment=production
&include_count=trueTo get counts for each facet, you can issue parallel queries with include_count=true and limit=0 (requesting only the count, not the entries):
async function getFacetCounts(topic: string) {
const regions = ["apac", "emea", "americas"];
const counts = await Promise.all(
regions.map(async (region) => {
const response = await fetch(
`${CDA_HOST}/v3/content_types/article/entries` +
`?query={"taxonomies.topic":{"$in":["${topic}"]},` +
`"taxonomies.region":{"$in":["${region}"]}}` +
`&environment=production&include_count=true&limit=0`,
{ headers: deliveryHeaders }
);
const data = await response.json();
return { region, count: data.count };
})
);
return counts;
}This pattern keeps facet counts accurate without over-fetching entry data.
Taxonomy-driven navigation menus
Taxonomy terms can also drive navigation structure. Fetching the full taxonomy tree lets you build dynamic menus:
async function getTopicNavigation() {
const response = await fetch(
`${CDA_HOST}/v3/taxonomies/topic/terms`,
{ headers: deliveryHeaders }
);
const { terms } = await response.json();
// terms is a hierarchical list:
// [{ uid: "technology", name: "Technology", children: [...] }, ...]
return terms;
}This means adding a new topic to the taxonomy automatically adds it to the navigation menu, without code changes or redeployment. The editorial team manages the classification vocabulary directly.
Combining taxonomies with other classification
In practice, you may use taxonomies alongside tags and references. The media company might use:
- Taxonomies for governed topic and region classification (powers navigation, filtering, content hubs)
- Tags for trending topic labels that editors apply ad hoc ("CES 2026", "Election Coverage") and that do not need hierarchical structure
- References for the author content type, which has its own profile page, headshot, and bio, making it a proper content entity rather than a classification term
This layered approach uses each mechanism for its intended purpose rather than forcing one to cover all classification needs.
Common mistakes
1. Using tags when you need governed classification
Freeform tags inevitably drift. After six months of editorial use, you end up with "AI", "A.I.", "artificial-intelligence", "Artificial Intelligence", and "ai" all meaning the same thing. Queries against these tags miss content because of inconsistent naming. If the classification drives user-facing navigation or filtering, use taxonomies with controlled terms.
2. Building reference-based categorization for cross-type classification
Creating a category content type and adding reference fields to articles, videos, and podcasts works, but querying "all content in the Technology category" requires three separate API calls, one per content type. Taxonomies provide this cross-type query natively. Reserve reference-based categorization for cases where the category itself is a rich content entity.
3. Creating overly deep taxonomy hierarchies
A taxonomy tree with six levels of nesting (Topic > Subtopic > Sub-subtopic > ...) creates editorial friction. Editors must navigate deep trees to find the right term, and queries against deep hierarchies become complex. Keep taxonomy depth to three levels maximum. If you need more granularity, consider splitting into separate taxonomies rather than deepening one.