# Workflow, Branches, and Collaboration

### About this export

| Field | Value |
| --- | --- |
| **content_type** | course |
| **platform** | contentstack-academy |
| **source_url** | https://www.contentstack.com/academy/courses/workflow-branches-and-collaboration |
| **language** | en |
| **product_area** | Contentstack Academy |
| **learning_path** | cms-developer-certification |
| **course_id** | workflow-branches-and-collaboration |
| **slug** | workflow-branches-and-collaboration |
| **version** | 2026-07-31 |
| **last_updated** | 2026-08-03 |
| **status** | published |
| **keywords** | ["Contentstack Academy"] |
| **summary_one_line** | Workflow, Branches, and Collaboration Learn how to scale a Contentstack implementation operationally through workflow design, automation, branching, and safer collaboration between developers and editors. Who This Course… |
| **total_duration_minutes** | 49 |
| **lessons_count** | 9 |
| **video_lessons_count** | 0 |
| **text_lessons_count** | 9 |
| **linked_learning_path** | cms-developer-certification |
| **linked_assessment_ref** | LMS_UNCONFIGURED_COURSE_ASSESSMENT |
| **markdown_file_url** | /academy/md/courses/workflow-branches-and-collaboration.md |
| **generated_at** | 2026-08-03T11:49:53.633Z |
| **intended_audience** | [] |
| **prerequisites** | [] |
| **related_courses** | [] |

> **Academy MD v3** — companion `.md` for Ask AI. Quizzes and graded assessments are **LMS-only**; this file never contains answer keys.

## Course Overview

| Metadata | Value |
| --- | --- |
| Catalog duration | 48m 45s |
| Released (if known) | 2026-07-31 |
| Product area | Contentstack Academy |

### Description

# Workflow, Branches, and Collaboration

Learn how to scale a Contentstack implementation operationally through workflow design, automation, branching, and safer collaboration between developers and editors.

## Who This Course Is For

This course is for teams that need governance without bottlenecks, especially when multiple developers, editors, or release streams are working at once.

## You Will Be Able To

*   design workflow stages that support quality control and editorial velocity
*   explain how branches support parallel schema and content work
*   reduce release risk by coordinating people, process, and platform features

## Recommended Preparation

Complete Courses 1-4 first so workflow, publishing, preview, and content delivery already feel concrete.

## Estimated Effort

1 hour

## Build Thread

You will move the Veda storefront from single-team learning into real operational ownership with approvals, branch hygiene, and coordinated publishing.

## Suggested Next Step

Start with [Content lifecycle](/course-5-workflow-branches-collaboration/module-5-1-workflow-and-content-lifecycle/01-content-lifecycle).

### Learning objectives

1. Follow each lesson in order.
2. Practice in a training stack using placeholders **YOUR_STACK_API_KEY** and **YOUR_DELIVERY_TOKEN** in local `.env` files only.
3. Validate API responses against the official documentation.

### Topics covered

Contentstack Academy

## Course structure

```text
workflow-branches-and-collaboration/
├── 01-workflow-and-content-lifecycle-overview · text · 1 min
├── 02-content-lifecycle-draft-review-publish · text · 1 min
├── 03-designing-workflows-stages-publish-rules-and-permissions · text · 1 min
├── 04-automation-hub-triggers-connectors-and-workflow-automation · text · 1 min
├── 05-branches-and-parallel-work-overview · text · 3 min
├── 06-why-branches-exist-and-when-to-use-them · text · 1 min
├── 07-compare-and-merge-branch-reconciliation-mechanics · text · 1 min
├── 08-supporting-parallel-development-and-content-work · text · 1 min
├── 09-avoiding-branch-sprawl-and-maintaining-hygiene · text · 1 min
```

## Lessons

### Lesson 01 — Workflow and Content Lifecycle : Overview

<!-- ai_metadata: {"lesson_id":"01","type":"text","duration_minutes":1,"topics":["Workflow","and","Content","Lifecycle","Overview"]} -->

#### Lesson text

# Workflow and Content Lifecycle

This module shows how content moves from draft to delivery, and how workflows and automation keep that movement reliable.

## Why This Module Matters

A strong content model is not enough if the operational path from creation to publication is inconsistent, opaque, or too easy to bypass.

## You Will Be Able To

*   describe the content lifecycle from draft through review, approval, and publish
*   design workflow stages that support both governance and editorial speed
*   identify where automation reduces manual coordination and failure risk

## Recommended Preparation

Complete Courses 3 and 4 first so environments, preview, and releases already feel grounded.

## Estimated Effort

60-75 minutes

## Practice Focus

Review the Veda storefront lifecycle and decide where editors, reviewers, publishers, and automation should each participate.

## Suggested Next Step

Start with lesson 1 in this module and map every stage to a real responsibility on your team.

#### Key takeaways

- Connect **Workflow and Content Lifecycle : Overview** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 02 — Content lifecycle - draft, review, publish

<!-- ai_metadata: {"lesson_id":"02","type":"text","duration_minutes":1,"topics":["Content","lifecycle","draft","review","publish"]} -->

#### Lesson text

# Content lifecycle: draft, review, publish

> **TL;DR**
> 
> *   Every entry moves through workflow stages (Draft, Review, Approved, Published) that control who can act on it next.
> *   Publishing is a separate action from workflow transitions, an "Approved" entry is not automatically live.
> *   Publish rules tie workflow stages to environments, protecting production from unapproved content.

Content does not appear on a website the moment someone types it into a CMS. Between creation and delivery, every piece of content passes through a series of states that determine its visibility, its readiness, and who is allowed to act on it next. Contentstack formalizes this progression through a workflow engine that tracks where each entry sits in its lifecycle and controls how it moves forward.

## The stages of the content lifecycle

Every entry in Contentstack moves through a predictable lifecycle: creation, editing, review, approval, publishing, and (optionally) unpublishing. Contentstack implements this through configurable workflow stages, role-based permissions, and explicit publishing actions, giving you precise control over each transition.

## Contentstack's default workflow stages

Every new stack ships with a default workflow containing four stages:

Stage

Purpose

Draft

Entry is being authored or edited

Review

Entry is under editorial review

Approved

Entry has been approved for publishing

Published

Entry has been published to at least one environment

flowchart LR
    Draft -->|Editor submits| Review
    Review -->|Reviewer approves| Approved
    Review -->|Reviewer rejects| Draft
    Approved -->|Publish action| Published
    Published -->|Unpublish| Approved
    Published -->|Edit| Draft

New entries start in Draft. When ready, the editor transitions them to Review. A reviewer either sends the entry back to Draft (with feedback) or advances it to Approved. From Approved, someone with publishing permissions publishes to one or more environments. The "Published" stage is set automatically by the system when the publish action completes, you do not move entries to it manually.

## How the workflow engine works

The workflow engine operates on a few core principles:

*   **Entries exist in exactly one workflow stage at any time.** The current stage is a single, definitive state.
*   **Transitions can be manual or automatic.** With Automation Hub, transitions can be triggered based on events or conditions.
*   **Stages can have permission restrictions.** For example, only "Editors" might move entries from Draft to Review, and only "Managing Editors" from Review to Approved.
*   **The workflow stage is visible throughout the UI.** Colored labels in the entry list let teams filter by stage, essential for managing a review queue.

## Publishing is separate from workflow stages

> **Common pitfall:**
> 
> An entry in the "Approved" stage is not automatically published. Publishing and workflow status are independent dimensions, always check both when debugging content visibility.

The publish action is not a workflow transition. An entry can be Approved yet published to zero environments, or published to staging while still in Review (if publish rules allow it).

The publish action works like this: select entries, choose target environment(s) and locale(s), optionally schedule, and confirm. The entry enters the publish queue and is processed asynchronously.

If an article is in the "Approved" workflow stage but has not been published to production, the delivery API query will not return it. The workflow stage and the published state are completely independent dimensions.

## Unpublishing: removing content without deleting it

Unpublishing removes an entry from a specific environment's delivery API without deleting the entry from Contentstack. The entry remains in the CMS with all its content, history, and metadata intact. It simply stops being delivered to the specified environment.

This is useful in several scenarios:

*   **Seasonal content:** a holiday promotion needs to be removed from production after the holiday, but kept in the CMS for next year.
*   **Corrections:** an article with factual errors needs to be pulled from the live site while it is corrected, then republished.
*   **Environment-specific visibility:** content might be unpublished from production but remain published to staging for QA testing.

Unpublishing is environment-specific. Unpublishing an entry from production does not affect its presence in staging or development. Each environment maintains its own independent publish state.

## The relationship between workflow stages and environments

Workflow stages and environments interact through publish rules, which you configure to enforce governance. The most common pattern ties the ability to publish to specific environments to the entry's current workflow stage:

Workflow stage

Allowed environments

Draft

None

Review

development, staging

Approved

development, staging, production

This configuration means that an entry in the Draft stage cannot be published to any environment. An entry in Review can be published to development and staging (for QA verification), but not to production. Only entries that have reached the Approved stage can be published to production.

This pattern gives teams a way to preview content in non-production environments during the review process while protecting the production environment from unapproved content. The workflow stages act as gates, and the publish rules act as the locks on those gates.

Configuring this relationship is covered in detail in the next lesson on designing workflows.

## Bulk workflow operations

When a team manages hundreds of entries, moving them one at a time through workflow stages is not practical. Contentstack supports bulk workflow operations:

*   **Bulk stage transition:** select multiple entries from the entry list and move them all to a different workflow stage in a single action.
*   **Bulk publish:** select multiple entries and publish them to one or more environments simultaneously.
*   **Bulk unpublish:** remove multiple entries from an environment at once.

These bulk operations respect the same permission rules as individual operations. If a user does not have permission to move entries to the "Approved" stage, a bulk transition to "Approved" will fail for those entries while succeeding for others where the user has the necessary permission. Bulk operations are accessible from the entry list view by selecting multiple entries using the checkboxes and choosing the desired action from the toolbar.

## Example: content lifecycle at a news organization

Consider a digital news organization that publishes 40 articles per day. Their workflow mirrors a traditional newsroom:

**Reporters create articles.** They fill in the headline, body text, hero image, category tags, and author reference. The article starts in the Draft stage. A reporter might save the article multiple times as they write, add quotes, and attach images.

**Section editors review articles.** A reporter moves the completed article to the Review stage. The section editor for that category (Sports, Politics, Business) reads the article, checks facts, verifies image credits, and either sends it back to Draft with comments or advances it to Approved.

**The managing editor makes the final call.** Articles in the Approved stage are reviewed by the managing editor during the daily editorial meeting. The managing editor may reorder publication priority, adjust headlines, or hold articles for a later date.

**The publishing desk executes the publish.** An operations team member publishes approved articles to the production environment. They may also schedule articles for timed release - an interview set to go live at 6 AM, or an earnings report timed to market close.

In this setup, the workflow stages map directly to newsroom roles:

Role

Creates entries

Moves to Review

Moves to Approved

Publishes to production

Reporter

Yes

Yes

No

No

Section Editor

No

No

Yes

No

Managing Editor

No

No

Yes

No

Publishing Desk

No

No

No

Yes

Each role has clear responsibilities, and the workflow engine enforces those boundaries. A reporter cannot publish directly to production, and the publishing desk cannot bypass the editorial review process.

## Viewing workflow state across the stack

Contentstack provides several views for monitoring workflow state:

*   **Entry list filtering:** filter entries by workflow stage to see all content currently in "Review," for example.
*   **Workflow stage column:** the entry list displays the current workflow stage for each entry as a visual indicator.
*   **Audit log:** every workflow transition is recorded in the audit log, showing who moved which entry to which stage and when.
*   **Dashboard widgets:** Contentstack's dashboard can surface workflow-related metrics.

For teams managing high volumes of content, the ability to filter by workflow stage and sort by last-modified date is essential for identifying bottlenecks. If 30 articles are stuck in "Review" and only 2 are in "Approved," the review team is the bottleneck.

## Common mistakes

### Mistake 1: Confusing workflow stage with publish state

An entry in the "Approved" stage is not published. An entry that is published is not necessarily in the "Published" workflow stage (it might still show "Approved" if the workflow does not include a post-publish stage update). These are two separate systems. Workflow tracks editorial readiness. Publishing controls delivery availability. Always check both dimensions when troubleshooting why content is or is not appearing on your site.

### Mistake 2: Skipping the review stage for "small changes"

A common justification for bypassing workflow is "it's just a typo fix." Typo fixes are how broken links, deleted paragraphs, and accidental field clears reach production. The workflow exists to catch mistakes, and mistakes do not scale with the perceived size of the change. Keep the workflow intact for all content changes, or explicitly carve out a fast-track workflow for minor edits with its own review step.

### Mistake 3: Publishing to production from the wrong workflow stage

Without publish rules configured, any user with publish permissions can publish any entry to any environment regardless of its workflow stage. This defeats the purpose of having a workflow at all. Always configure publish rules to restrict which stages can publish to which environments, as described in the next lesson.

#### Key takeaways

- Connect **Content lifecycle - draft, review, publish** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 03 — Designing workflows - stages, publish rules, and permissions

<!-- ai_metadata: {"lesson_id":"03","type":"text","duration_minutes":1,"topics":["Designing","workflows","stages","publish","rules","and"]} -->

#### Lesson text

# Designing workflows: stages, publish rules, and permissions

> **TL;DR**
> 
> *   Custom workflows let you add stages (e.g., Legal Review, Compliance) tailored to your content governance needs.
> *   Publish rules enforce which workflow stages can publish to which environments -- without them, workflow stages are advisory only.
> *   Match the number of stages to your team size and content risk; over-engineering creates friction without adding safety.

The default workflow in Contentstack - Draft, Review, Approved, Published - is a starting point, not a destination. Real organizations have content governance requirements that do not fit into four generic stages. A pharmaceutical company needs regulatory sign-off. A financial services firm requires compliance review. A global retailer needs regional marketing approval before localized content goes live. Contentstack's workflow engine is fully configurable, and designing the right workflow is one of the highest-leverage decisions a developer makes when setting up a stack.

## Creating custom workflow stages

You configure workflows in Contentstack through Settings > Workflows in the stack dashboard. From here, you can modify the default workflow or create entirely new workflows.

Each workflow consists of an ordered set of stages. A stage has:

*   Name: a human-readable label like "Legal Review" or "Compliance Check."
*   Color: a visual indicator that appears in the entry list, making it easy to spot entries at different stages.
*   Description: an optional explanation of what should happen at this stage.
*   Permissions: which roles can transition entries into and out of this stage.

To create a custom workflow, navigate to Settings > Workflows and click "Add Workflow." You define your stages in sequence, configure transition rules, and assign the workflow to one or more content types.

Here is what a custom workflow for a regulated industry might look like:

Stage

Color

Description

Draft

Gray

Content is being authored

Editorial Review

Blue

Editor checks tone, accuracy, and completeness

Legal Review

Yellow

Legal team reviews for compliance

Final Approval

Green

Senior stakeholder signs off

Each stage represents a gate. Content cannot skip stages unless you explicitly allow it through transition rules or superuser permissions.

## Configuring stage transitions

Stage transitions define which stages an entry can move to from its current stage. By default, transitions are linear - Draft to Editorial Review to Legal Review to Final Approval. But Contentstack supports non-linear transitions as well.

Common transition patterns include:

*   **Linear progression:** Draft > Review > Approved. Simple, predictable, works for most editorial workflows.
*   **Rejection loops:** from any review stage, the entry can be sent back to Draft. This allows reviewers to request changes without approving incomplete content.
*   **Parallel paths:** from Draft, an entry might go to either "Technical Review" or "Editorial Review" depending on the content type, then both paths converge at "Final Approval."
*   **Skip paths:** certain roles might be allowed to skip intermediate stages. A managing editor might move an entry directly from Draft to Approved for breaking news.

When configuring transitions in the Contentstack UI, you specify for each stage which other stages it can transition to. An entry in "Legal Review" might be allowed to transition to either "Final Approval" (if approved) or back to "Draft" (if changes are required). It would not be allowed to transition directly to a "Published" state, since that bypasses the final approval gate.

## Publish rules: controlling who can publish where

Publish rules are the enforcement mechanism that connects workflow stages to environments. Without publish rules, workflow stages are advisory - they indicate where content is in the process, but they do not prevent anyone from publishing to any environment.

Publish rules change that. They restrict the publish action based on the entry's current workflow stage and the target environment.

You configure publish rules in **Settings > Workflows > Publish Rules**. A publish rule consists of:

*   Content type(s): which content types the rule applies to (or all content types).
*   Workflow stage: the stage the entry must be in.
*   Environment: the environment the entry can be published to.
*   Approvers (optional): specific users or roles that must approve the publish action.

For example, a publish rule for a pharmaceutical company workflow:

Rule

Content types

Required stage

Allowed environment

1

All

Draft

development

2

All

Editorial Review

development, staging

3

All

Legal Review

staging

4

All

Final Approval

staging, production

This configuration means: content in Draft can only be published to the development environment. Content that has passed Editorial Review can go to development or staging. Content that has cleared Legal Review can be published to staging (for final verification). Only content that has reached Final Approval can be published to production.

If an editor tries to publish a Draft entry to production, Contentstack blocks the action. The publish rules are enforced at the platform level, not through client-side validation that could be bypassed.

## Role-based permissions on workflow transitions

Workflow permissions control who can move entries between stages. This is distinct from publish rules (which control publishing to environments). Workflow permissions control the editorial process itself.

In Contentstack, you configure these permissions through the role system. Navigate to **Settings > Roles** and edit a role to define its workflow permissions:

*   **Content Author role:** can create entries (Draft stage), can transition from Draft to Editorial Review. Cannot transition to any other stage.
*   **Editor role:** can transition from Editorial Review to Legal Review (approve) or from Editorial Review back to Draft (reject). Cannot transition to Final Approval.
*   **Legal Reviewer role:** can transition from Legal Review to Final Approval (approve) or from Legal Review back to Draft (reject). Cannot modify earlier transitions.
*   **Managing Editor role:** can transition from Final Approval to any stage. Can also publish to production.

These permissions create a chain of responsibility. Each role handles one part of the lifecycle and cannot interfere with other parts. The Content Author writes and submits. The Editor reviews and forwards to Legal. Legal reviews and forwards to the Managing Editor. The Managing Editor gives final approval and authorizes publishing.

// Checking an entry's current workflow stage via the Management API
const response = await fetch(
  \`https://api.contentstack.io/v3/content\_types/product\_monograph/entries/${entryUid}\`,
  {
    headers: {
      api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
      authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
    },
  }
);

const entry = await response.json();
const workflowStage = entry.entry.\_workflow?.name;
console.log(\`Current stage: ${workflowStage}\`);
// Output: "Current stage: Legal Review"

## Workflow assignment by content type

Different content types can have different workflows. This is a powerful capability that reflects a simple reality: not all content requires the same governance.

A blog post might need a two-stage workflow: **Draft > Review > Publish**. A product safety data sheet might need a five-stage workflow with legal and compliance gates. A press release might need management approval. A social media snippet might need only a single review.

In Contentstack, you assign workflows to content types in the workflow configuration:

*   **Settings > Workflows > select a workflow > Content Type Assignment**
*   Choose which content types use this workflow

If a content type has no assigned workflow, entries of that type use the default workflow. If you want different governance levels for different content, create multiple workflows and assign them to the appropriate content types.

For a pharmaceutical company:

Content type

Assigned workflow

Product Monograph

Regulated Content Workflow

Press Release

PR Approval Workflow

Blog Post

Editorial Workflow

Internal Memo

Simple Draft-Publish

Each workflow has stages, permissions, and publish rules appropriate to the content's regulatory exposure.

## Superuser bypass

Some roles need the ability to bypass workflow stages entirely. In Contentstack, users with the Owner role or specific administrative permissions can move entries to any workflow stage regardless of transition rules.

This is intentional. Emergency content updates - a product recall notice, a security advisory, a breaking news correction - cannot wait for a five-stage approval process. The superuser bypass provides an escape valve. However, every bypass is logged in the audit trail. The workflow is bypassed, not invisible. If a superuser moves an entry directly from Draft to production, the audit log records exactly who did it and when.

The key is not to prevent bypasses - it is to make them visible and exceptional. If your team routinely uses superuser bypass, your workflow has too many stages for your operational reality.

## Webhook integration with workflow transitions

Workflow transitions can trigger webhooks, enabling integration with external systems. This is configured in **Settings > Webhooks**, where you create a webhook that fires on specific workflow events.

Common webhook triggers for workflow transitions:

*   **Entry moves to "Review":** notify the review team via an external notification system.
*   **Entry moves to "Approved":** trigger a staging deployment in your CI/CD pipeline.
*   **Entry is published:** invalidate CDN cache or trigger a static site rebuild.

// Webhook payload received when an entry changes workflow stage
// POST https://your-api.example.com/contentstack-webhook
{
  "event": "content\_types.entries.workflows.update",
  "data": {
    "entry": {
      "uid": "blt\_matrix\_link\_001",
      "title": "Atorvastatin Calcium Tablets - Product Monograph",
      "content\_type": "product\_monograph"
    },
    "workflow": {
      "name": "Regulated Content Workflow",
      "stage": {
        "name": "Final Approval",
        "uid": "blt\_digital\_dawn\_001"
      }
    }
  }
}

This webhook payload can trigger external compliance tracking infrastructure to record approvals, update internal ticket references, or send real-time notifications to stakeholders.

For more complex automation scenarios that go beyond simple webhook calls, Contentstack's Automation Hub provides a visual flow builder - covered in the next lesson.

## The workflow API

Contentstack exposes workflow operations through the Content Management API. This allows you to build custom workflow tools, dashboards, or integrations.

Key endpoints include:

*   GET /v3/workflows: list all workflows in the stack.
*   GET /v3/workflows/{workflow\_uid}: get details of a specific workflow, including its stages.
*   POST /v3/content\_types/{content\_type\_uid}/entries/{entry\_uid}/workflow: change an entry's workflow stage programmatically.

// Moving an entry to the next workflow stage via API
const response = await fetch(
  \`https://api.contentstack.io/v3/content\_types/product\_monograph/entries/${entryUid}/workflow\`,
  {
    method: "POST",
    headers: {
      api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
      authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      workflow: {
        workflow\_stage: {
          uid: legalReviewStageUid,
          comment: "Editorial review complete. Forwarding to legal.",
        },
      },
    }),
  }
);

The API respects the same permission rules as the UI. If the management token's associated user does not have permission to transition to the specified stage, the API returns an error, preventing programmatic bypass of workflow governance.

## Designing for your team size

A common mistake is over-engineering workflows. The right number of stages depends on your team, your content risk profile, and your publishing velocity.

*   **Small team (2-3 people):** a two-stage workflow (Draft > Ready to Publish) is usually sufficient. Everyone knows what everyone else is working on. Adding five stages creates friction without adding safety.
*   **Medium team (5-15 people):** a three- or four-stage workflow (Draft > Review > Approved) makes sense. Reviewers need a formal queue. Approvers need visibility into what has been reviewed. Publish rules protect production from unapproved content.
*   **Large team (15+ people):** role-specific stages become necessary. Different teams handle different review gates. Workflow stages map to organizational responsibilities, not just content readiness levels.
*   **Regulated content:** add stages for each required compliance gate, regardless of team size. A two-person team managing pharmaceutical content still needs Legal Review and Compliance Approval stages because the regulatory requirement exists independent of team size.

The general principle: add a workflow stage only when you need a distinct person or team to take a distinct action at that point in the lifecycle. If two stages are always handled by the same person in the same sitting, merge them into one.

## Example: pharmaceutical company with regulatory requirements

A pharmaceutical company publishes product monographs, patient information leaflets, and healthcare professional communications. All of these are regulated documents. The workflow must ensure that every published document has been reviewed by both the medical writing team and the legal/compliance team.

Their custom workflow:

1.  **Draft:** a medical writer creates or updates the document.
2.  **Medical Review:** a senior medical writer reviews for scientific accuracy and alignment with the approved product label.
3.  **Legal Review:** the legal team reviews for regulatory compliance, ensuring claims are supported and disclaimers are present.
4.  **Compliance Approval:** the compliance officer signs off, confirming the document meets all applicable regulations.
5.  **Final Approval:** the publications manager gives final sign-off and authorizes publishing.

Publish rules for this workflow:

*   Entries in Draft, Medical Review, or Legal Review can only be published to the internal-review environment (an internal preview site accessible only to the review team).
*   Entries in Compliance Approval can be published to staging for final layout and formatting verification.
*   Only entries in Final Approval can be published to production (the public-facing website).

Role restrictions

*   **Medical writers:** Can only transition entries from Draft to Medical Review.
*   **Senior medical writers:** Can transition from Medical Review to Legal Review or back to Draft.
*   **Legal reviewers:** Can transition from Legal Review to Compliance Approval or back to Draft.
*   **The compliance officer:** Can transition from Compliance Approval to Final Approval or back to Legal Review.
*   **The publications manager:** Can execute the final publish action to production from the Final Approval stage.

This workflow adds complexity, but the complexity is justified by regulatory requirements. Every transition is logged, every approval is traceable, and no document reaches the public without passing through all required gates.

## Common mistakes

> **Common pitfall:**
> 
> Workflow stages without publish rules are advisory only -- an entry in "Draft" can still be published to production if no publish rule prevents it. Always configure publish rules alongside your workflow stages.

### Mistake 1: Creating stages without assigning permissions

A workflow stage without role-based permissions is just a label. If anyone can move an entry to "Approved," the stage provides no governance value. You'll want to configure which roles can transition to each stage when you create the stage.

### Mistake 2: Building workflows that match the org chart rather than the content process

Workflows should reflect the content lifecycle, not the organizational hierarchy. If you have stages for "VP Review" and "Director Review" but both stakeholders are checking the same things, you have two stages where one would suffice. Design stages around distinct review activities, not job titles.

### Mistake 3: Forgetting to configure publish rules alongside workflow stages

Workflow stages without publish rules are advisory only. An entry can be in "Draft" and still published to production if no publish rule prevents it. Workflows and publish rules must be configured together to provide actual governance.

#### Key takeaways

- Connect **Designing workflows - stages, publish rules, and permissions** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 04 — Automation - triggers, connectors, and workflow automation

<!-- ai_metadata: {"lesson_id":"04","type":"text","duration_minutes":1,"topics":["Automation","triggers","connectors","and","workflow","automation"]} -->

#### Lesson text

# Automation Hub: triggers, connectors, and workflow automation

> **TL;DR:**
> 
> *   Automation Hub connects CMS events (publish, stage change, asset upload) to actions (Slack messages, Jira tickets, auto-publish) without custom code.
> *   Scope triggers narrowly to avoid noisy, high-volume automation runs.
> *   Automations execute asynchronously and independently — design each flow to be self-contained.

Workflows define the stages content moves through. Automation Hub defines what happens automatically when content moves. It is Contentstack's built-in automation engine - a visual flow builder that connects CMS events to actions without requiring you to write webhook handlers, deploy serverless functions, or maintain integration infrastructure. When an entry is published, Automation Hub can notify a Slack channel. When content moves to a review stage, it can assign a reviewer. When an asset is uploaded, it can create a task in Jira. These automations run inside the Contentstack platform, configured through a drag-and-drop interface in the Automate section of your stack.

## Where Automation Hub fits in the platform

Automation Hub sits between Contentstack's event system and external services. Every action in Contentstack generates events: entries are created, updated, published, unpublished, or deleted; assets are uploaded or removed; workflow stages change; releases are deployed. Without Automation Hub, the only way to react to these events is through webhooks - which require you to build, host, and maintain an endpoint that receives the event payload and executes logic.

Automation Hub eliminates that infrastructure layer for common automation patterns. Instead of deploying a Lambda function that listens for a webhook and posts to Slack, you configure a flow in the Automation Hub UI: trigger on “entry published,” action is “send Slack message.” The automation runs on Contentstack's infrastructure.

This does not replace webhooks entirely. Webhooks remain the right choice for custom integrations, complex business logic, or scenarios where you need full control over the processing pipeline (as covered in the webhooks lesson in Course 6). Automation Hub is for the 80% of automation needs that follow a trigger-action pattern and do not require custom code.

## Triggers: what starts an automation

A trigger is the event that initiates an automation flow. You configure triggers in the Automation Hub flow builder by selecting from a list of supported CMS events.

Common triggers include:

Trigger

Fires when

Entry created

A new entry is created in any (or a specific) content type

Entry updated

An existing entry is saved with changes

Entry published

An entry is published to any (or a specific) environment

Entry unpublished

An entry is unpublished from an environment

Entry deleted

An entry is permanently deleted

Workflow stage changed

An entry moves to a different workflow stage

Asset uploaded

A new asset is uploaded to the stack

Asset published

An asset is published to an environment

Release deployed

A release is deployed to an environment

Triggers can be scoped. You do not have to react to every entry creation across every content type. You can configure a trigger to fire only when entries of a specific content type are created, or only when entries are published to a specific environment, or only when entries move to a specific workflow stage.

This scoping is important for avoiding noisy automations. A trigger that fires on every entry update across all content types will generate enormous volumes of automation executions, most of which are irrelevant. Scope triggers as narrowly as possible.

## Actions: what the automation does

An action is the operation performed when a trigger fires. Actions connect to internal Contentstack operations or external services.

Internal actions operate within Contentstack:

*   Move to workflow stage: automatically advance or revert an entry's workflow stage.
*   Update entry field: set or modify a field value on the entry that triggered the automation.
*   Publish entry: publish the triggering entry to a specified environment.
*   Create a task: generate a task assigned to a specific user or role.
*   Send email notification: send an email to specified recipients with customizable content.

External actions connect to third-party services through pre-built connectors:

*   Send Slack message: post a message to a Slack channel or direct message.
*   Send Microsoft Teams message: post a notification to a Teams channel.
*   Create Jira issue: create a ticket in a Jira project.
*   Call webhook: send an HTTP request to any external URL (for services without a dedicated connector).

Each action in a flow can reference data from the trigger event. When the trigger is “entry published,” the action can include the entry title, the content type, the environment it was published to, and the user who performed the publish. This contextual data makes notifications and external records meaningful rather than generic.

## Connectors: pre-built integrations

Connectors are Automation Hub's pre-built bridges to external services. Instead of configuring raw HTTP requests, you authenticate a connector once and then use it across multiple automations.

Setting up a connector typically involves:

1.  Navigate to the Automate section of your stack.
2.  Select a connector (e.g., Slack).
3.  Authenticate by providing the required credentials or completing an OAuth flow.
4.  The connector is now available for use in any automation flow within the stack.

Available connectors include:

*   Slack: post messages, create channels, add reactions.
*   Microsoft Teams: send messages, create cards.
*   Jira: create issues, update issues, add comments.
*   Asana: create tasks, update task status.
*   Email (SMTP): send emails through your configured mail service.
*   Generic webhook: call any HTTP endpoint for services without a dedicated connector.

Connectors handle authentication, retry logic, and payload formatting. When you add a “Send Slack message” action to a flow, you select the authenticated Slack connector, choose the channel, and compose the message using template variables from the trigger data. You do not manage OAuth tokens, handle token refresh, or format Slack API payloads.

## Building an automation: the visual flow builder

The Automation Hub flow builder is accessed through the Automate section of your Contentstack stack. Building an automation follows a consistent pattern:

1.  Create a new automation: click “New Automation” and give it a descriptive name (e.g., “Notify editors on new campaign entry”).
2.  Configure the trigger: select the event type and scope it to the relevant content type, environment, or workflow stage.
3.  Add actions: add one or more actions that execute when the trigger fires. Actions execute sequentially.
4.  Add conditional logic (optional): insert if/then branches to route the automation based on field values, content type, or other criteria.
5.  Test the automation: use the test function to simulate a trigger event and verify the actions execute correctly.
6.  Activate the automation: enable the automation to start processing real events.

Here is a concrete example. You want to notify a Slack channel whenever a blog post is published to production:

Trigger configuration:

*   Event: Entry published
*   Content type: Product
*   Environment: production

Action configuration:

*   Action: Send Slack message
*   Connector: (your authenticated Slack connector)
*   Channel: #content-published
*   Message template:

New blog post published to production:
Title: {{entry.title}}
Product: {{entry.title}}
URL: {{entry.url}}
Published by: {{user.name}}

The template variables (wrapped in double curly braces) are populated from the trigger event data. When the automation fires, the Slack message contains the actual entry title, author, URL, and the name of the user who clicked “Publish.”

## Conditional logic: if/then branching

Not every trigger event should produce the same action. Automation Hub supports conditional branching that evaluates entry data to determine which path the automation follows.

Consider a scenario where different regional editors should be notified based on the entry's locale:

Trigger: Entry moved to “Review” stage in the “Campaign” content type.

Condition: Check the value of the region field.

*   If region equals “EMEA”: send Slack message to #emea-editors.
*   If region equals “APAC”: send Slack message to #apac-editors.
*   If region equals “Americas”: send Slack message to #americas-editors.
*   Default: send Slack message to #global-editors.

Conditional logic uses field values from the entry, metadata from the event (like the environment name or the user who triggered the event), and comparison operators (equals, contains, starts with, is empty).

You can also chain conditions. An automation might first check the content type, then check a field value, then check the target environment before deciding which action to execute. This allows a single automation to handle complex routing without requiring separate automations for each scenario.

## Practical automation patterns

### Pattern 1: Auto-assign reviewer on stage transition

Trigger: Entry moves to “Review” stage.

Action: Update the entry's “assigned\_reviewer” field based on the content type.

Why: eliminates the manual step of assigning a reviewer, reducing the time entries spend waiting in the review queue.

### Pattern 2: Notify Slack on publish

Trigger: Entry published to “production” environment.

Action: Send Slack message to the #content-live channel with entry title, URL, and publisher name.

Why: keeps the team informed about what is going live without requiring anyone to monitor the Contentstack publish queue.

### Pattern 3: Create Jira ticket on review rejection

Trigger: Entry moves from “Review” back to “Draft” stage.

Action: Create a Jira issue in the “Content Fixes” project, populated with the entry title, the reviewer's comments, and a link to the entry in Contentstack.

Why: ensures rejected content gets tracked in the team's project management tool rather than relying on the author to notice the stage change.

### Pattern 4: Auto-publish to staging on approval

Trigger: Entry moves to “Approved” stage.

Action: Publish the entry to the “staging” environment.

Why: eliminates the manual step of publishing approved content to staging for final QA verification. The content appears on the staging site automatically once it is approved.

### Pattern 5: Send stakeholder summary on release deployment

Trigger: Release deployed to “production” environment.

Action: Send email to a distribution list with the release name, the number of entries included, and the deployment timestamp.

Why: provides stakeholders with a record of content deployments without requiring them to log into Contentstack.

## Limitations and operational considerations

Automation Hub is powerful, but it operates within specific constraints that affect how you design automations.

Asynchronous execution. Automations do not execute synchronously with the triggering event. When an editor publishes an entry, the publish action completes, and the automation runs afterward. There is a small delay between the trigger event and the action execution. This means you cannot use Automation Hub for actions that must complete before the triggering operation finishes.

No guaranteed execution order. If multiple automations are triggered by the same event, execution order is not guaranteed. An automation that sends a Slack notification and another that updates a field might execute in either order. Design automations to be independent of each other - do not assume one automation's action will complete before another automation starts.

Rate limits. Automation Hub enforces rate limits on automation executions. High-volume operations - like bulk-publishing 500 entries - can trigger 500 automation executions simultaneously, potentially hitting rate limits. Plan for this by using bulk operations judiciously and designing automations that handle rate-limited responses gracefully.

Connector authentication expiry. OAuth tokens for connectors (Slack, Jira, etc.) can expire. If a connector's authentication becomes invalid, all automations using that connector will fail silently or with errors. Monitor connector health and re-authenticate proactively before tokens expire.

> **Common pitfall:**
> 
> There is no “undo” for automation actions. If a misconfigured flow publishes an entry to production prematurely, you have to reverse it manually. Always test automations against non-production content before activating them.

**No rollback:** If an automation performs an undesired action (e.g., publishing an entry to production prematurely), no automatic undo exists. The action has to be manually reversed. Test automations thoroughly before activating them on production content.

## Example: marketing team campaign automation

The Veda marketing team uses Contentstack to manage campaign content. They have a “Product Line” content type with fields for collection name, description, launch date, hero image, and locale. The team wants three automations to streamline their process.

Automation 1: Notify design team on new campaign creation.

*   Trigger: Entry created in the “Product Line” content type.
*   Action: Send Slack message to #design-requests with the campaign name, region, and launch date.
*   Result: the design team learns about new campaigns immediately and can begin preparing visual assets without waiting for a manual handoff.

Automation 2: Auto-assign regional editor based on locale.

**Trigger:** Entry created in the “Product Line” content type.

*   Condition: Check the locale field value.
*   If locale is fr-FR: set assigned\_editor to “Marie Dupont.”
*   If locale is de-DE: set assigned\_editor to “Klaus Weber.”
*   If locale is en-US: set assigned\_editor to “Sarah Johnson.”

*   Action: Update the entry's assigned\_editor field with the matched editor.
*   Result: campaigns are automatically routed to the correct regional editor based on the target locale, eliminating the manual assignment step.

Automation 3: Send stakeholder summary on campaign publish.

*   Trigger: Entry published to “production” in the “Product Line” content type.
*   Action: Send email to the marketing-stakeholders distribution list.
*   Email content includes: campaign name, region, locale, launch date, and the URL where the campaign page is live.
*   Result: stakeholders receive a professional summary of every campaign launch without needing access to Contentstack or monitoring the publish queue.

These three automations together eliminate three manual coordination steps: design handoff, editor assignment, and stakeholder notification. The content team's workflow becomes: create campaign > content is automatically routed and design team is notified > write and review content > publish > stakeholders are automatically informed.

## Common mistakes

### Mistake 1: Building automations that depend on execution order

If you create two automations on the same trigger - one that sets a field value and another that reads that field value - the reading automation may execute before the writing automation. Design each automation to be self-contained. If you need sequential operations, put them in a single automation flow as ordered actions.

### Mistake 2: Not scoping triggers to specific content types

A trigger configured as “on any entry published” will fire for every content type in the stack. If your stack has 20 content types and you only care about blog posts, the automation runs 19 times unnecessarily for every non-blog-post publish. Always scope triggers to the specific content type, environment, or workflow stage that matters.

### Mistake 3: Forgetting to test automations with realistic data

The Automation Hub test function simulates trigger events, but the test data may not reflect production scenarios. An automation that works with a test entry might fail on a real entry with empty fields, special characters in the title, or unexpected locale values. Test with entries that represent the full range of content your team produces.

#### Key takeaways

- Connect **Automation - triggers, connectors, and workflow automation** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 05 — Branches and Parallel Work : Overview

<!-- ai_metadata: {"lesson_id":"05","type":"text","duration_minutes":3,"topics":["Branches","and","Parallel","Work","Overview"]} -->

#### Lesson text

# Branches and Parallel Work

This module explains how Contentstack branches support parallel schema and content changes without destabilizing the main line of work.

## Why This Module Matters

As teams grow, change cannot happen serially. Branching lets you isolate experiments, launches, and structural work while preserving production stability.

## You Will Be Able To

*   explain when a branch is the right tool instead of a new environment
*   compare and merge branch changes with less guesswork
*   maintain branch hygiene so parallel work does not turn into content drift

## Recommended Preparation

Complete Module 5.1 first and make sure environments versus branches is already clear from Course 3.

## Estimated Effort

60-75 minutes

## Practice Focus

Use Veda examples to separate feature work, model evolution, and production-safe delivery paths across branches.

## Suggested Next Step

Start with lesson 1 in this module and pay attention to how branch responsibilities differ from environment responsibilities.

#### Key takeaways

- Connect **Branches and Parallel Work : Overview** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 06 — Why branches exist and when to use them

<!-- ai_metadata: {"lesson_id":"06","type":"text","duration_minutes":1,"topics":["Why","branches","exist","and","when","use"]} -->

#### Lesson text

# Why branches exist and when to use them

> **TL;DR:**
> 
> *   Contentstack branches fork content type schemas (not code) so you can iterate on structural changes without disrupting production.
> *   Stack-level resources (environments, webhooks, workflows, roles) are shared across all branches.
> *   Use branches for breaking schema changes; use workflow stages and environments for content-only isolation.

Branches in Contentstack are not git branches. Misunderstanding this leads to architectural mistakes that take weeks to unwind. Git branches create parallel versions of code files. Contentstack branches create parallel versions of your content model - the content type definitions, global fields, and optionally the entries that conform to those schemas. They exist to solve a specific problem: how do you make structural changes to your content types without disrupting the production content that editors are actively publishing?

## The problem branches solve

Imagine you have a “Product” content type with 12 fields, and your production e-commerce site renders products based on that schema. Your frontend code expects those 12 fields, in that structure, with those data types. Now your team needs to restructure the Product content type: add a “specifications” modular block, rename the “description” field to “short\_description,” add a new “long\_description” rich text field, and remove the deprecated “legacy\_sku” field.

Without branches, you have two options:

**Option 1:** Make changes directly on the live content type. The moment you add “specifications” and remove “legacy\_sku,” every delivery API response for Product entries changes shape. Your frontend code, which expects the old schema, breaks. If your site is server-rendered, pages start throwing errors. If it is statically generated, the next rebuild fails. Your editors, who are trying to publish product updates during a sale event, are blocked.

**Option 2:** Coordinate a synchronized cutover. You plan the content type changes, prepare the frontend code, and deploy everything simultaneously during a maintenance window. This works for small changes but becomes a high-risk, high-coordination effort for significant schema restructuring. If anything goes wrong during the cutover, you are rolling back both CMS changes and frontend code under pressure.

Branches provide a third option: create a branch, make all your schema changes there, test them, update your frontend code against the branch's API, and merge when everything is validated. The production content model remains untouched until you are ready.

## What branches include

A branch in Contentstack is a fork of specific stack resources at a point in time. When you create a branch from main, the branch receives copies of:

*   Content type definitions: every content type's schema (fields, field types, validations, options) is duplicated on the branch. Changes to content types on the branch do not affect main, and vice versa.
*   Global field definitions: shared field groups used across content types are also branched. Modifying a global field on a branch does not change the global field on main.
*   Entries (optionally): depending on your configuration, entries can be included in the branch. This gives you content to test against your modified schemas.

After creation, the branch evolves independently. If you add a field to the “Product” content type on the branch, the main branch's “Product” content type still has the original schema. The two versions diverge, and reconciling them is a deliberate merge operation (covered in the next lesson).

## What branches do NOT include

> **Common pitfall:** Stack-level settings (environments, webhooks, workflows, roles) are not branched. Modifying a webhook on the stack affects events on all branches, plan accordingly.

Several stack-level resources are not branched:

*   Environments: development, staging, production - these are stack-wide. A branch does not get its own set of environments.
*   Delivery tokens: tokens are scoped to environments, not branches. However, you use a branch-specific delivery URL or parameter to fetch content from a specific branch.
*   Webhooks: webhook configurations are stack-level. Creating a branch does not duplicate your webhook setup.
*   Workflows: workflow configurations exist at the stack level. Entries on a branch follow the same workflow rules as entries on main.
*   Roles and permissions: user roles and their permissions apply across all branches.
*   Automation Hub configurations: automations operate at the stack level.

This design reflects the fact that branches are for content model development, not for creating isolated operational environments. If you need separate environments for testing, use Contentstack environments (covered in Course 3). If you need separate content for different regions, use localization. Branches solve the schema evolution problem specifically.

## The main branch

Every Contentstack stack has a main branch by default. This is the production branch - the one your delivery tokens serve content from, the one your editors work in, and the one your frontend application queries against. The main branch is always present and cannot be deleted.

All other branches are created from main (or from other branches). When you create a branch called feature/product-redesign, it forks from the current state of main. From that point forward, the two branches are independent.

The main branch is special in one important way: it is the default target for API queries. When you make a delivery API request without specifying a branch, you get content from main. This means your production site continues working exactly as before when you create a new branch - nothing changes until you explicitly merge branch changes back to main.

## Creating a branch

You create branches through the Contentstack UI or the API.

Through the UI: navigate to **Settings > Branches** and click “Add Branch.” You provide:

*   A branch name (unique within the stack)
*   A source branch to fork from (usually main)

Through the API: use the Content Management API to create a branch programmatically.

// Creating a new branch via the Management API
const response = await fetch(
  "https://api.contentstack.io/v3/stacks/branches",
  {
    method: "POST",
    headers: {
      api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
      authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      branch: {
        uid: "feature-product-redesign",
        source: "main",
      },
    }),
  }
);

const result = await response.json();
console.log(\`Branch created: ${result.branch.uid}\`);
// Output: "Branch created: feature-product-redesign"

Branch creation is not instantaneous for large stacks. Contentstack needs to duplicate all content type definitions (and optionally entries) to the new branch. For a stack with 30 content types and thousands of entries, this may take a few minutes. The API returns immediately with the branch metadata, and the branch becomes available once the duplication process completes.

## Branch scope: a snapshot that evolves

A critical concept is that a branch is a snapshot of content types at the time of creation, which then evolves independently. This has two implications:

Changes on the branch do not affect main. You can add fields, remove fields, create new content types, and restructure schemas on the branch without any impact on the main branch. Editors working on main see no changes. The delivery API for main returns the same content in the same structure as before.

Changes on main do not affect the branch. If an editor adds a new entry on main, that entry does not appear on the branch. If a developer adds a field to a content type on main (for example, a quick fix), that field does not appear on the branch's version of that content type. The branch and main diverge from the moment of creation.

This divergence is both the power and the risk of branches. The longer a branch lives, the more it diverges from main, and the harder the eventual merge becomes. This lifecycle management challenge is addressed in the lesson on avoiding branch sprawl.

## Querying content from a branch

To test your schema changes against actual API responses, you need to query content from the branch rather than from main. The delivery API supports branch-specific queries through a request header.

// Fetching products from a specific branch
import contentstack from "@contentstack/delivery-sdk";

const stack = contentstack.stack({
  apiKey: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
  deliveryToken: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_DELIVERY\_TOKEN!,
  environment: "development",
  branch: "feature-product-redesign",
});

// This returns entries using the branch's content type schema
const result = await stack
  .contentType("product")
  .entry()
  .query()
  .find();

// The response shape reflects the branch's schema,
// including the new "specifications" modular block
result.entries.forEach((product: any) => {
  console.log(product.title);
  console.log(product.specifications); // new field from the branch
});

By specifying the branch parameter, you get content shaped according to the branch's content type definitions. This is how your frontend development team can build and test against the new schema before it reaches main.

## When to use branches

Branches are the right tool when you need to make structural changes to your content model that cannot be done safely on main. Specific scenarios include:

**Adding a new content type that requires iteration.** You are building a “Video” content type with embedded metadata, transcription references, and platform-specific encoding fields. The content type needs several rounds of refinement before it is ready for editors to use. Creating it on a branch lets you iterate without polluting the main branch with half-finished content types.

**Restructuring an existing content type.** You need to convert the “Article” content type from a flat field structure to one that uses modular blocks for the body section. This is a breaking change - existing entries and frontend code depend on the current structure. A branch lets you make the change, migrate test entries, and validate the new structure before applying it to main.

**Running a large migration.** You are migrating from a legacy content model to a new one. The migration involves renaming fields, changing field types, and adding new required fields across multiple content types. A branch provides a sandbox for the entire migration, letting you validate the result before committing to main.

**Coordinating frontend and CMS changes.** Your frontend team needs to rebuild the homepage component to support a new layout. The new layout requires different fields in the “Page” content type. The frontend team works against the branch's API, building and testing the new component while the production site continues serving the old layout from main.

## When NOT to use branches

Branches are not a general-purpose isolation mechanism. They solve the content model evolution problem, and using them for other purposes creates confusion and overhead.

Do not use branches for content-only changes. If you need to create, edit, or delete entries without changing the content type schema, you do not need a branch. Work on main. Branches add complexity that is only justified when the content model itself is changing.

Do not use branches for environment isolation. If you need to test content in a staging context, use Contentstack environments (as covered in Course 3). Environments control where content is published. Branches control how content is structured. These are different concerns.

Do not use branches for small, non-breaking field additions. Adding an optional field to a content type does not break existing entries or API responses. The new field appears with a null value on existing entries, and the delivery API returns it only when populated. This kind of change can be made directly on main without risk.

Do not use branches for urgent hotfixes. If you need to add a field immediately to support a production fix, creating a branch, making the change, and merging back adds unnecessary delay. Make the change on main, deploy the frontend update, and move on.

## Example: restructuring content types for a media company

A media company runs a news website built on Contentstack. Their current content model has an “Article” content type with a single rich text field for the body and a “Video” content type that only stores a URL and a title. The development team needs to:

1.  Add a “Video” content type with full metadata: title, description, duration, thumbnail, platform (YouTube, Vimeo, self-hosted), transcript reference, and encoding specifications.
2.  Restructure the “Article” content type to use modular blocks for the body, allowing editors to mix text blocks, embedded videos, pull quotes, and image galleries.
3.  Add a “Gallery” content type for image collections.

All three changes are structural and would break the existing production site if applied directly to main. The team creates a branch called feature/media-redesign:

*   On the branch, they build the new “Video” content type with all its fields.
*   They modify the “Article” content type to use modular blocks.
*   They create the “Gallery” content type.
*   They create test entries to validate the new schemas.
*   The frontend team queries the branch's API to build new components for videos, modular article bodies, and galleries.
*   Once everything is validated, they merge the branch back to main and deploy the frontend changes simultaneously.

Throughout this process, the production site runs uninterrupted. Editors continue publishing articles with the old flat body field. The delivery API for main continues serving the existing schema. The branch changes are invisible to everyone outside the development team until the merge is executed.

## Common mistakes

### Mistake 1: Treating Contentstack branches like git branches

Git branches create parallel versions of code files and merge line-by-line. Contentstack branches create parallel versions of content type schemas and merge at the field level. The mental model, the merge mechanics, and the conflict resolution are all different. Do not assume your git branch workflow translates directly to Contentstack branches.

### Mistake 2: Creating branches for content editing rather than schema changes

If an editor wants to draft 20 articles without affecting the live site, they do not need a branch. They need to use the Draft workflow stage and not publish to production. Branches exist for content model changes, not content changes. Using branches for editorial isolation creates unnecessary merge complexity and confuses the team about what branches are for.

### Mistake 3: Forgetting that stack-level settings are not branched

A developer creates a branch and expects the branch to have its own webhook configurations, its own workflow stages, or its own delivery tokens. It does not. These are stack-level resources shared across all branches. If you modify a webhook on the stack, it applies to events on all branches. Plan accordingly.

#### Key takeaways

- Connect **Why branches exist and when to use them** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 07 — Compare and merge - branch reconciliation mechanics

<!-- ai_metadata: {"lesson_id":"07","type":"text","duration_minutes":1,"topics":["Compare","and","merge","branch","reconciliation","mechanics"]} -->

#### Lesson text

# Compare and merge: branch reconciliation mechanics

> **TL;DR:**
> 
> *   Always use the compare view before merging — it shows field-level additions, removals, and modifications across content types.
> *   Field removal in a merge means permanent data loss on existing entries; verify before proceeding.
> *   Merges cannot be automatically reversed; create a backup branch from the target before merging.

Creating a branch is straightforward. Merging it back is where the real work happens. A branch that has been evolving independently for days or weeks contains content type changes that must be reconciled with whatever has happened on the target branch in the same period. Contentstack provides a compare-and-merge workflow that lets you inspect differences between branches at the field level, understand what will change, and execute the merge with confidence. Skipping the comparison step or rushing the merge is how teams break production content models.

> **Common pitfall:**
> 
> When a merge removes a field from a content type, all data in that field on existing entries is permanently deleted. There is no undo. Always verify that removed-field data has been migrated or is genuinely no longer needed before merging.

## The compare feature

Before merging anything, you need to see exactly what has changed. The compare feature shows the differences between two branches - typically your working branch and main - at the content type and field level.

You access the compare view from **Settings > Branches** in the Contentstack UI. Select your branch and click “Compare” to see a side-by-side diff against the target branch (usually main).

The compare view organizes differences into three categories:

**Added content types:** content types that exist on your branch but not on the target. These were created on the branch after it was forked. Merging will add these content types to the target branch.

**Modified content types:** content types that exist on both branches but have different schemas. The compare view shows field-level differences: which fields were added, removed, or changed on each branch.

**Deleted content types:** content types that exist on the target branch but were removed from your branch. Merging will remove these content types from the target. This is a destructive operation and requires careful consideration - deleting a content type on the target branch also removes all entries of that type.

## Field-level diff

The compare view does not just tell you that a content type was modified. It shows exactly what changed at the field level:

Diff type

What it means

Field added

A new field exists on the branch that does not exist on target

Field removed

A field was deleted on the branch that still exists on target

Field modified

A field exists on both branches but has different properties

For modified fields, the diff shows what changed: the field type, the display name, validation rules, default values, field-level help text, or whether the field is required. This granularity is essential for understanding the impact of a merge.

Consider a “Product” content type where the branch made these changes:

Product content type diff:
+ specifications (modular\_blocks)     -  new field added on branch
+ long\_description (rich\_text)        -  new field added on branch
~ description → short\_description     -  field renamed on branch
- legacy\_sku (text)                   -  field removed on branch

This diff tells you exactly what will happen to the Product content type on main if you merge: two new fields appear, one field gets renamed, and one field is removed. The removed field means any data in legacy\_sku on main branch entries will be lost after merge. The renamed field means frontend code referencing description must be updated to reference short\_description.

## The merge operation

Once you have reviewed the diff and are confident in the changes, you execute the merge. The merge applies all changes from the source branch to the target branch.

Through the UI: from the compare view, click “Merge.” Contentstack shows a summary of all changes that will be applied and asks for confirmation.

Through the API: use the branch merge endpoint.

// Merging a branch into main via the Management API
const response = await fetch(
  "https://api.contentstack.io/v3/stacks/branches\_merge",
  {
    method: "POST",
    headers: {
      api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
      authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      base\_branch: "main",
      compare\_branch: "feature-product-redesign",
      merge\_strategy: "merge\_prefer\_base",
      merge\_comment: "Merging product redesign: new specifications block, description rename, legacy\_sku removal",
    }),
  }
);

const result = await response.json();
console.log(\`Merge status: ${result.merge\_details.status}\`);

The merge operation is not instantaneous. Contentstack processes the changes asynchronously, applying field additions, removals, and modifications to the target branch's content types. For large merges affecting many content types, this may take several minutes.

## What happens during a merge

Understanding the mechanics of a merge helps you predict its impact and plan accordingly.

**New content types** are created on the target branch with the same schema they have on the source branch. If your branch added a “Gallery” content type with 8 fields, the target branch gets a “Gallery” content type with those same 8 fields. No entries are created - only the content type definition is merged.

**Modified content types** have their schemas updated to reflect the branch's changes. Added fields appear on the target. Removed fields disappear from the target. Modified fields take on the branch's configuration. Existing entries on the target branch are affected:

*   New fields appear with empty/null values on existing entries.
*   Removed fields and their data are gone. Entries that had data in those fields lose it.
*   Modified fields retain their data but the field properties (validation, help text, etc.) change.

**Deleted content types** are removed from the target branch, along with all their entries. This is the most destructive merge outcome and should be reviewed carefully.

## Conflict resolution

Conflicts arise when both branches modify the same content type. If your branch renamed a field from description to short\_description and main independently added a validation rule to the description field, a conflict appears: the field the main branch modified no longer exists in the same form on your branch.

Contentstack resolves conflicts using a selected merge strategy, not a universal “source wins” rule. Common strategies include:

*   merge\_prefer\_base (default): prefer target/base branch values on conflicts.
*   merge\_prefer\_compare: prefer source/compare branch values on conflicts.
*   overwrite\_with\_compare: force compare branch values over base.
*   merge\_new\_only: merge only additions and leave existing conflicting definitions unchanged.

This means you must choose a strategy intentionally and review the compare diff before merging.

For complex conflicts, the recommended approach is:

1.  Compare your branch to the target and identify all conflicts.
2.  Decide how each conflict should be resolved.
3.  If the chosen strategy will not produce the correct result, update your branch (or change the strategy) before merging.
4.  Re-compare to confirm the merge will produce the desired result.
5.  Execute the merge.

## Pre-merge checklist

Before executing any merge, work through this checklist:

**Review all content type changes.** Use the compare view to inspect every added, modified, and deleted content type. Understand the impact of each change on existing entries and frontend code.

**Check for field removals.** Any field removed by the merge means data loss for entries on the target branch that used that field. Verify that the data is no longer needed, or that it has been migrated to a different field.

**Verify that target branch content types will not break existing entries.** If you are adding a required field, existing entries on the target branch will be invalid until they are updated. Consider making new fields optional during the merge, then making them required after existing entries are populated.

**Coordinate with the frontend team.** If the merge changes the delivery API response shape (new fields, removed fields, renamed fields), the frontend code must be updated. Plan the merge and the frontend deployment together.

**Communicate with the content team.** Editors working on main should know that content type changes are coming. If the merge modifies content types they actively use, they may encounter new fields, changed field labels, or modified validation rules.

**Choose your timing.** Merge during low-traffic periods when fewer editors are actively working. A merge that changes the schema of a content type currently being edited can create confusion.

// Pre-merge: list all content types on both branches to audit differences
async function auditBranchDifferences(sourceBranch: string, targetBranch: string) {
  const fetchContentTypes = async (branch: string) => {
    const response = await fetch(
      "https://api.contentstack.io/v3/content\_types",
      {
        headers: {
          api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
          authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
          branch,
        },
      }
    );
    const data = await response.json();
    return data.content\_types;
  };

  const sourceTypes = await fetchContentTypes(sourceBranch);
  const targetTypes = await fetchContentTypes(targetBranch);

  const sourceUids = new Set(sourceTypes.map((ct: any) => ct.uid));
  const targetUids = new Set(targetTypes.map((ct: any) => ct.uid));

  const added = sourceTypes.filter((ct: any) => !targetUids.has(ct.uid));
  const removed = targetTypes.filter((ct: any) => !sourceUids.has(ct.uid));

  console.log(\`Content types added on ${sourceBranch}: ${added.map((ct: any) => ct.uid).join(", ")}\`);
  console.log(\`Content types removed on ${sourceBranch}: ${removed.map((ct: any) => ct.uid).join(", ")}\`);
}

auditBranchDifferences("feature-product-redesign", "main");

## Post-merge actions

The merge is not the end of the process. Several follow-up actions are required to ensure the merged content model works correctly.

**Verify the merged content types.** Open each modified content type on the target branch and confirm the schema matches your expectations. Check field order, field types, validation rules, and display names.

**Test the delivery API.** Query the delivery API for affected content types and verify the response shape. New fields should appear (with null or empty values on existing entries). Removed fields should be absent. Renamed fields should use the new name.

// Post-merge: verify the delivery API returns the expected schema
const stack = contentstack.stack({
  apiKey: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
  deliveryToken: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_DELIVERY\_TOKEN!,
  environment: "development",
  // No branch parameter  -  querying main after merge
});

const result = await stack
  .contentType("product")
  .entry()
  .query()
  .find();

const sampleProduct = result.entries\[0\];
console.log("Has specifications:", "specifications" in sampleProduct);
console.log("Has short\_description:", "short\_description" in sampleProduct);
console.log("Has legacy\_sku:", "legacy\_sku" in sampleProduct);
// Expected: true, true, false

**Update frontend code.** Deploy frontend changes that align with the new content model. If you renamed description to short\_description, your frontend components need to use the new field name. Ideally, the frontend code is already prepared (tested against the branch API) and just needs to be deployed.

**Re-publish affected entries.** If content type structure changed in ways that affect delivery, existing entries may need to be re-published. An entry published before the merge was published with the old schema. Re-publishing it ensures the delivery API serves it with the new schema.

**Populate new required fields.** If the merge added required fields, existing entries on the target branch are now technically invalid. Editors need to update those entries with values for the new required fields before they can be saved or re-published.

## Entry handling during merge

Entries on the source branch and entries on the target branch are largely independent. The merge operation focuses on content type schemas, not entries. However, the schema changes affect entries indirectly:

*   Entries on the target branch that belong to modified content types will reflect the new schema after merge. New fields appear empty. Removed fields and their data are gone.
*   Entries that were created on the source branch are not automatically copied to the target branch during a merge. Only the content type definitions are merged.
*   If you need entries from the source branch on the target branch, you must handle that separately - either through export/import, the Management API, or manual re-creation.

This is an important distinction. A merge moves schema changes, not content. If your branch had test entries that you want to keep, plan for their migration separately.

## Limitations: merges cannot be automatically reversed

There is no “undo merge” button in Contentstack. Once a merge is executed, the target branch's content types are permanently modified. If the merge introduced a problem, you have a few remediation options:

*   Manual revert: modify the target branch's content types to restore the pre-merge state. This is tedious but possible for small changes.
*   Restore from a backup branch: if you created a backup branch from the target before merging (a recommended practice), you can compare the backup to the current state and selectively revert changes.
*   Re-create and re-merge: if the merge was fundamentally wrong, you may need to create a new branch from the backup, apply only the correct changes, and merge again.

The irreversibility of merges is why the pre-merge checklist and the compare review matter. Review every change before merging.

## Example: merging a redesign branch with a conflict

Veda has been working on a feature/homepage-redesign branch for two weeks. On this branch, they:

1.  Added a “modular\_blocks” field called components to the “Page” content type, replacing the old hero\_image and hero\_title fields.
2.  Created a new “Product Line” content type with 10 fields.
3.  Removed the deprecated “Legacy Banner” content type.

During the same two weeks, a developer on main independently added a promotional\_image field to the “Page” content type to support a short-term promotion.

When the team runs the compare view, they see:

Page content type:

*   Branch added: components (modular\_blocks)
*   Branch removed: hero\_image (file), hero\_title (text)
*   Main added: promotional\_image (file) - this is a conflict area

Product Line content type:

*   Entirely new on the branch. Will be added to main.

Legacy Banner content type:

*   Deleted on the branch. Will be removed from main (and all its entries).

The conflict on the Page content type is that the branch does not have the promotional\_image field that main added. If they merge directly, promotional\_image will be removed from main (because it does not exist on the branch).

The resolution process:

1.  The team adds the promotional\_image field to the Page content type on the branch, preserving the main branch's addition.
2.  They re-run the compare and confirm that promotional\_image now appears on both branches (no conflict).
3.  They verify that the “Legacy Banner” content type's entries are no longer needed.
4.  They execute the merge.
5.  Post-merge, they verify that Page has components, promotional\_image, and no longer has hero\_image or hero\_title.
6.  They deploy the updated frontend that renders the new modular hero sections.
7.  They schedule the eventual removal of promotional\_image once the promotion ends.

## Common mistakes

### Mistake 1: Merging without reviewing the compare diff

Every merge has the potential to remove fields, delete content types, and change data structures. Merging without reviewing the diff is equivalent to deploying code without reading the pull request. Always use the compare view before merging, even for branches where you think you know what changed.

### Mistake 2: Forgetting that field removal means data loss

When a merge removes a field from a content type, all data in that field on existing entries is permanently deleted. This is not a reversible operation. Before merging a branch that removes fields, verify that the data in those fields is either migrated to a new location or genuinely no longer needed.

### Mistake 3: Not coordinating the merge with frontend deployment

A merge that changes the delivery API response shape (new fields, removed fields, renamed fields) without a corresponding frontend update results in a broken site. Plan merges and frontend deployments as a coordinated operation. The ideal sequence is: deploy frontend code that handles both old and new schemas, execute the merge, then deploy frontend code that only handles the new schema.

#### Key takeaways

- Connect **Compare and merge - branch reconciliation mechanics** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 08 — Supporting parallel development and content work

<!-- ai_metadata: {"lesson_id":"08","type":"text","duration_minutes":1,"topics":["Supporting","parallel","development","and","content","work"]} -->

#### Lesson text

# Supporting parallel development and content work

> **TL;DR:**
> 
> *   Use branch naming conventions (feature/, migration/, fix/) to signal purpose and expected lifespan.
> *   Sequence merges from smallest/most isolated to broadest to minimize conflicts.
> *   Point QA builds at specific branches via the branch SDK parameter to test schema changes without affecting production.

A single branch serving a single team is manageable. Three branches serving three teams while editors publish fifty entries a day on main is where branch strategy becomes an engineering discipline. Contentstack branches enable parallel workstreams, but the coordination between those workstreams - sequencing merges, testing in isolation, communicating changes, and keeping content editors productive - requires deliberate planning. Without it, branches solve the schema isolation problem while creating a coordination problem that is equally painful.

## The parallel development scenario

Consider a large media company running a website on Contentstack. Three teams are working simultaneously:

**Team A: Homepage redesign.** The design team is restructuring the homepage content type to use modular blocks instead of fixed fields. This involves adding new block types (hero carousel, featured stories grid, breaking news banner), removing legacy fields, and modifying the page layout reference structure. Estimated duration: 6 weeks.

**Team B: Product catalog launch.** The business team is adding an entirely new section to the site - a product catalog with “Product,” “Category,” and “Product Review” content types. This is net-new content modeling that does not modify existing content types. Estimated duration: 4 weeks.

**Team C: Article format migration.** The editorial technology team is migrating the “Article” content type from a flat rich text body to a structured modular blocks body, enabling inline embeds, pull quotes, and interactive elements. This modifies the most heavily used content type in the stack. Estimated duration: 3 weeks.

Meanwhile, the content team publishes 50 articles per day on main. Editors create entries, move them through workflow stages, and publish to production without interruption.

Each of these three teams creates a branch:

*   feature/homepage-redesign
*   feature/product-catalog
*   migration/article-v2

From this point, the teams work independently on their branches. The question is: how do you coordinate this parallel work so that each team can develop, test, and merge without breaking each other or the production site?

## Branch naming conventions

Consistent branch naming is not cosmetic - it tells every team member what a branch is for, what kind of changes it contains, and how long it should live.

A practical naming convention:

Prefix

Purpose

Example

feature/

New functionality or content type additions

feature/product-catalog

redesign/

Structural changes to existing content types

redesign/homepage-modular

migration/

Content model migrations (field type changes, renames)

migration/article-v2

fix/

Small structural fixes (rare - usually done on main)

fix/missing-seo-fields

experiment/

Exploratory changes not yet committed to a roadmap

experiment/personalization-ct

Include enough detail in the branch name to convey the scope. feature/new-stuff is useless. feature/product-catalog-with-reviews tells the team exactly what is being built.

Avoid special characters, spaces, and excessively long names. Stick to lowercase alphanumeric characters, hyphens, and forward slashes. Contentstack branch UIDs have character limits, so keep names concise but descriptive.

## Testing on branches

Each branch produces its own version of the content model, and you need to verify that your frontend code works against that model. Contentstack supports branch-specific API queries, which means you can build and test your frontend against a branch without affecting main.

### Branch-specific delivery URLs

When you initialize the Contentstack SDK or make direct API calls, you specify the branch to query:

// next.config.ts  -  branch-aware configuration for QA testing
import contentstack from "@contentstack/delivery-sdk";

const branch = process.env.NEXT\_PUBLIC\_CONTENTSTACK\_BRANCH || "main";

const stack = contentstack.stack({
  apiKey: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
  deliveryToken: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_DELIVERY\_TOKEN!,
  environment: "development",
  branch: branch,
});

export default stack;

By setting the NEXT\_PUBLIC\_CONTENTSTACK\_BRANCH environment variable in your deployment configuration, you can point any frontend build at any branch. Your QA environment can build against feature/homepage-redesign while your staging environment continues to build against main.

### CI/CD integration

Configure your build pipeline to build from a specific branch for QA testing. A typical setup:

<# Example CI/CD configuration for branch-specific builds
# .github/workflows/branch-qa.yml
name: Branch QA Build

on:
  workflow\_dispatch:
    inputs:
      contentstack\_branch:
        description: "Contentstack branch to build against"
        required: true
        default: "main"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: npm ci
      - name: Build with branch-specific content
        env:
          NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY: ${{ secrets.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY }}
          NEXT\_PUBLIC\_CONTENTSTACK\_DELIVERY\_TOKEN: ${{ secrets.NEXT\_PUBLIC\_CONTENTSTACK\_DELIVERY\_TOKEN }}
          NEXT\_PUBLIC\_CONTENTSTACK\_ENVIRONMENT: development
          NEXT\_PUBLIC\_CONTENTSTACK\_BRANCH: ${{ github.event.inputs.contentstack\_branch }}
        run: npm run build
      - name: Deploy to QA
        run: npm run deploy:qa/pre>

This workflow lets a developer trigger a QA build against any Contentstack branch. Team A can build against feature/homepage-redesign to test their new modular homepage. Team C can build against migration/article-v2 to test the new article rendering. Both builds run independently against their respective branch schemas.

### Verifying branch content via API

Before committing to a frontend build, you can verify the branch's content type schema and entries directly through the API.

// Verify that the branch's content types match expectations
async function verifyBranchSchema(branch: string) {
  const response = await fetch(
    "https://api.contentstack.io/v3/content\_types/product",
    {
      headers: {
        api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
        authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
        branch,
      },
    }
  );

  const data = await response.json();
  const fields = data.content\_type.schema.map((f: any) => f.uid);

  console.log(\`Fields on "${branch}" branch:\`, fields);
  // On feature/product-catalog: \["title", "slug", "price", "category", "description", "images", "specifications"\]
  // On main: content type does not exist yet
}

verifyBranchSchema("feature/product-catalog");

## Coordination patterns: sequencing merges

When multiple branches exist simultaneously, the order in which you merge them matters. Merging branches in the wrong sequence can create conflicts that did not exist when the branches were created.

### Independent branches merge cleanly

Team B's feature/product-catalog branch adds new content types without modifying existing ones. This branch can be merged at any time without conflicting with other branches. It does not touch any content types that Team A or Team C are modifying.

### Overlapping branches require sequencing

Team A's redesign/homepage-modular and Team C's migration/article-v2 both modify existing content types. If they both modify a shared global field (for example, an “SEO” global field used by both Homepage and Article), the second merge will encounter the first merge's changes.

The recommended sequencing strategy:

  1.  Merge the smallest, most isolated branch first. Team B's product catalog branch adds new content types and does not conflict with anything. Merge it first.
  2.  Merge branches that modify fewer content types next. Team C's article migration touches one content type. Merge it second.
  3.  Merge the broadest branch last. Team A's homepage redesign is the most extensive. Merge it last, after incorporating any changes from the prior merges.

Before each merge, re-compare the branch against the current state of main (which now includes the previously merged changes). This ensures you see any new conflicts introduced by earlier merges.

>   
> 
> **Common pitfall:** Contentstack has no built-in “rebase” operation. If your branch diverges significantly from main, you'll need to create a fresh branch from current main and manually re-apply your changes — a labor-intensive process that grows worse the longer the branch lives.

### Rebasing a branch

If a branch has been living for a long time and main has changed significantly, you may need to incorporate main's changes into your branch before merging. Instead of a git-style rebase:

  1.  Note the changes on your branch.
  2.  Create a new branch from the current state of main.
  3.  Manually apply your changes to the new branch.
  4.  Delete the old branch.

This is labor-intensive, which is why keeping branches short-lived is so important (covered in the next lesson on avoiding branch sprawl).

## Communication practices

Branches are invisible to anyone who does not look for them. Without active communication, team members work in ignorance of what branches exist, what they contain, and when they will merge.

### Branch registry

Maintain a branch registry - a simple shared document that tracks active branches:

  

    

      

Branch name

      

Owner

      

Purpose

      

Created

      

Target merge date

      

Status

    

  

  

    

      

feature/product-catalog

      

Team B

      

New product catalog content types

      

2026-01-15

      

2026-02-10

      

In progress

    

    

      

redesign/homepage-modular

      

Team A

      

Homepage modular blocks redesign

      

2026-01-10

      

2026-02-20

      

In progress

    

    

      

migration/article-v2

      

Team C

      

Article body modular blocks

      

2026-01-20

      

2026-02-12

      

In progress

    

  

This registry does not need to be a sophisticated tool. A shared spreadsheet, a Notion page, or a pinned Slack message works. The point is visibility: everyone should be able to see what branches exist and when they are expected to merge.

### Pre-merge communication

Before merging a branch, notify the team:

  *   Inform editors that content type changes are coming. Specify which content types are affected and what editors should expect (new fields, changed labels, removed fields).
  *   Inform frontend developers that the delivery API schema is changing. Coordinate the frontend deployment with the merge.
  *   Inform other branch owners if the merge might affect their branch. If you are merging changes to a shared global field, other branch owners need to know so they can update their branches accordingly.

### Post-merge communication

After merging, confirm:

  *   Which content types changed and how.
  *   Whether editors need to take any action (populate new fields, update entries with changed validation).
  *   Whether the frontend deployment has been executed or is pending.
  *   Whether the merged branch has been deleted (to keep the branch list clean).

## When NOT to use branches

Branches introduce coordination overhead. That overhead is justified for structural content model changes but wasteful for simpler scenarios.

**Content-only changes.** Editors creating, editing, or deleting entries do not need branches. They work on main and use workflow stages plus publish rules to manage content visibility. Branches are for schema changes, not content changes (as established in the previous lesson on why branches exist).

**Small, non-breaking field additions.** Adding an optional text field to a content type does not break existing entries or API responses. Make the change directly on main. The new field appears with a null value on existing entries and adds no risk to the production site.

**Urgent hotfixes.** If a content type needs a field added or modified immediately to fix a production issue, creating a branch, making the change, and merging back is unnecessarily slow. Apply the fix directly to main and deploy the frontend update.

**Single-developer changes.** If one developer needs to add a field and can coordinate directly with the frontend deployment, a branch adds ceremony without benefit. Branches provide value when multiple people need to coordinate changes or when changes require extended development time.

## Example: media company parallel workstreams

Returning to the media company scenario, here is how the three teams coordinate their parallel work:

Week 1-2: all three teams create branches and begin development independently. The content team publishes 50 articles daily on main without interruption.

Week 3: Team C completes the article migration on their branch. They:

  1.  Run a compare against main and see no conflicts (no one else modified the Article content type on main).
  2.  Notify the content team that Article entries will gain new modular block fields.
  3.  Deploy the frontend update that handles both old and new article formats.
  4.  Merge migration/article-v2 to main.
  5.  Verify the merged Article content type on main.
  6.  Delete the migration/article-v2 branch.

Week 4: Team B completes the product catalog. They:

  1.  Run a compare against main. The Article content type now has modular blocks (from Team C's merge), but this does not affect the Product catalog, which is entirely new content types.
  2.  Merge feature/product-catalog to main.
  3.  Deploy the product catalog frontend pages.
  4.  Delete the feature/product-catalog branch.

Week 6: Team A completes the homepage redesign. They:

  1.  Run a compare against main and discover that main now includes changes from both Team C and Team B's merges. If any shared global fields were modified, they need to reconcile.
  2.  Update their branch to account for main's current state if necessary.
  3.  Notify the content team about Homepage content type changes.
  4.  Deploy the new homepage frontend.
  5.  Merge redesign/homepage-modular to main.
  6.  Delete the branch.

Throughout this six-week period, the production site ran without interruption. Editors continued their daily publishing work on main. Each team merged when they were ready, in a sequence that minimized conflicts.

## Common mistakes

### Mistake 1: All teams merging on the same day without coordination

If three branches merge to main within the same hour, each merge changes the schema, and subsequent merges may encounter unexpected differences from prior merges. Stagger merges and verify the state of main between each one.

### Mistake 2: Not testing the frontend against the branch before merging

A branch's content type changes are only validated when your frontend code successfully renders content using the branch's schema. If you merge first and test afterward, you are testing in production. Build and verify your frontend against the branch API before merging to main.

### Mistake 3: Forgetting to delete branches after merging

Merged branches that linger in the branch list confuse new team members, clutter the UI, and create ambiguity about whether the branch is still active. Delete branches immediately after a successful merge and post-merge verification. Branch lifecycle management is covered in detail in the next lesson.

## Self-check

  1.  Three teams each have a branch. Team A modifies the “Page” content type, Team B creates new content types, and Team C modifies the “Page” content type and the “Article” content type. In what order should they merge, and why?
  2.  Your QA team wants to preview the new product catalog schema (on branch feature/product-catalog) without affecting the staging site that serves content from main. Describe the SDK configuration and CI/CD changes you would make.
  3.  A developer proposes creating a branch to add a single optional “subtitle” field to the Blog Post content type. Is a branch appropriate here, and what would you recommend instead?

#### Key takeaways

- Connect **Supporting parallel development and content work** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

### Lesson 09 — Avoiding branch sprawl and maintaining hygiene

<!-- ai_metadata: {"lesson_id":"09","type":"text","duration_minutes":1,"topics":["Avoiding","branch","sprawl","and","maintaining","hygiene"]} -->

#### Lesson text

# Avoiding branch sprawl and maintaining hygiene

> **TL;DR:**
> 
> *   Set time limits: branches beyond 30 days should have someone actively justifying their existence.
> *   Assign a single person (tech lead or CMS architect) to own branch governance — shared responsibility means no responsibility.
> *   Delete branches immediately after a successful merge and post-merge verification.

A branch that exists for two weeks and gets merged is a tool. A branch that exists for six months and no one remembers why is a liability. Branch sprawl - the accumulation of stale, abandoned, or forgotten branches - is one of the most common operational problems in teams that adopt branching without establishing lifecycle discipline. Every unmerged branch represents divergence from main, and divergence that grows unchecked eventually makes merging so painful that teams avoid it entirely. At that point, the branches are not enabling parallel development. They are preventing integration.

## Why long-lived branches become liabilities

The core issue is divergence. When you create a branch, it captures a snapshot of your content model at that moment. From that point, the branch and main evolve independently. Every change made to main after the branch was created is a change the branch does not have. Every change made on the branch is a change main does not have. The gap between the two widens every day.

After one week, the gap is usually small - a few field additions or modifications on main. After one month, the gap may include new content types, modified global fields, and structural changes that affect multiple content types. After three months, the branch's view of the content model may be so different from main's current state that merging requires essentially rebuilding the branch's changes from scratch.

Long-lived branches also create operational confusion:

*   New team members encounter branches in the branch list and do not know if they are active, abandoned, or awaiting merge. They may accidentally work on a stale branch.
*   Branch list clutter makes it harder to find active branches in the Contentstack UI. When you have 15 branches and only 3 are active, finding the right one takes unnecessary effort.
*   Resource allocation is obscured. Branches that represent work-in-progress create a false sense that projects are active when they may have been abandoned or deprioritized.
*   Merge conflicts compound. The longer two branches diverge, the more conflicts accumulate. A branch that could have been cleanly merged after two weeks may require significant conflict resolution after two months.

## Branch lifecycle management

Every branch should follow a defined lifecycle: create, develop, test, merge, delete. Each phase has an expected duration, and exceeding that duration should trigger a review.

### Phase 1: Create

A branch is created in response to a specific need - a new content type, a schema restructuring, a migration. The creation should be accompanied by an entry in the branch registry (as described in the parallel development lesson) that records the branch name, owner, purpose, creation date, and expected merge date.

### Phase 2: Develop

The development phase is where schema changes are made on the branch. This should be time-boxed. Most content model changes - even complex ones - can be completed within 2-4 weeks. If development is taking longer, the scope may be too large and should be broken into smaller, independently mergeable pieces.

### Phase 3: Test

The testing phase validates the branch's changes against the frontend. Build your application against the branch's API, verify rendering, and confirm that the delivery API returns the expected response shapes. Testing should take days, not weeks.

### Phase 4: Merge

Execute the merge following the compare-and-merge process. Coordinate with the frontend deployment and communicate changes to the content team.

### Phase 5: Delete

After a successful merge and post-merge verification, delete the branch. There is no reason to keep a merged branch. It has served its purpose. Its changes are now on main. Keeping it around adds clutter and creates the false impression that it is still relevant.

## Setting time limits

Time limits are the simplest and most effective governance mechanism for branches. They do not require sophisticated tooling or complex processes - just a policy that the team agrees to follow.

A practical time limit policy:

Branch age

Action required

0-14 days

Normal development. No action needed.

14-30 days

Owner should provide a status update. Is the branch on track?

30-60 days

Branch requires a review. Is it still needed? Can the scope be reduced? Should it be rebased against current main?

60-90 days

Branch is flagged as at-risk. The team lead reviews whether to continue, reduce scope, or abandon.

90+ days

Branch is presumed stale unless the owner can justify its continued existence. Default action is to delete it.

These thresholds are guidelines, not rigid rules. A 3-month branch for a major platform migration might be justified. A 3-month branch for “adding a video content type” is not. The point is that every branch beyond 30 days should have someone actively justifying its existence.

> **Common pitfall:**
> 
> Deleting a branch is irreversible. If the branch contained unmerged schema changes you still need, they are gone. Always verify a successful merge before deleting.

## The delete operation

Deleting a branch removes it and its content type modifications permanently.

Through the UI: navigate to **Settings > Branches**, select the branch, and click “Delete.” Contentstack asks for confirmation.

Through the API: use the branch delete endpoint.

// Deleting a branch via the Management API
const response = await fetch(
  "https://api.contentstack.io/v3/stacks/branches/feature-product-catalog",
  {
    method: "DELETE",
    headers: {
      api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
      authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
    },
  }
);

if (response.ok) {
  console.log("Branch deleted successfully");
} else {
  const error = await response.json();
  console.error("Delete failed:", error.error\_message);
}

Before deleting, verify:

*   The branch has been successfully merged (if it contains changes you want to keep).
*   No frontend deployments are still pointing at the branch. A QA environment configured to build against a deleted branch will fail on its next build.
*   No team members are actively working on the branch. Communicate the deletion before executing it.

The main branch cannot be deleted. It is the permanent production branch of the stack.

## Who should manage branches

Branch governance works best when a single person or role owns the process. In most organizations, this is the technical lead, CMS architect, or lead developer - someone with visibility into all active development workstreams and the authority to enforce lifecycle policies.

The branch owner's responsibilities:

*   Create branches: approve branch creation requests and ensure they have a clear purpose, scope, and expected merge date.
*   Monitor branch age: regularly review the branch list and flag branches that are approaching or exceeding time limits.
*   Coordinate merges: sequence merges to minimize conflicts, as described in the parallel development lesson.
*   Enforce deletion: ensure branches are deleted after merging. Chase down owners of stale branches.
*   Maintain the branch registry: keep the shared document up to date with current branch status.

Without a designated owner, branch management becomes a shared responsibility that no one actually takes. Branches accumulate, merges are postponed, and the branch list grows until someone inherits the mess.

## Monitoring branch drift

For long-lived branches that are justified (major migrations, multi-month redesigns), periodically compare the branch to main to assess how much they have diverged. This is not the same as a pre-merge compare - it is a health check.

// Monitor branch drift by counting content type differences
async function assessBranchDrift(branchUid: string) {
  const fetchTypes = async (branch: string) => {
    const response = await fetch(
      "https://api.contentstack.io/v3/content\_types?include\_count=true",
      {
        headers: {
          api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
          authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
          branch,
        },
      }
    );
    return response.json();
  };

  const \[branchData, mainData\] = await Promise.all(\[
    fetchTypes(branchUid),
    fetchTypes("main"),
  \]);

  const branchUids = new Set(
    branchData.content\_types.map((ct: any) => ct.uid)
  );
  const mainUids = new Set(
    mainData.content\_types.map((ct: any) => ct.uid)
  );

  const onlyOnBranch = \[...branchUids\].filter((uid) => !mainUids.has(uid));
  const onlyOnMain = \[...mainUids\].filter((uid) => !branchUids.has(uid));

  console.log(\`Branch: ${branchUid}\`);
  console.log(\`Content types only on branch: ${onlyOnBranch.length}\`);
  console.log(\`Content types only on main: ${onlyOnMain.length}\`);
  console.log(\`Total divergence indicators: ${onlyOnBranch.length + onlyOnMain.length}\`);

  if (onlyOnMain.length > 0) {
    console.warn(
      \`Warning: main has ${onlyOnMain.length} content types that this branch does not. \` +
      \`Consider updating the branch to incorporate these changes.\`
    );
  }
}

assessBranchDrift("redesign-homepage-modular");

If the drift assessment reveals significant divergence, the branch owner has two options:

1.  Rebase the branch: create a new branch from current main and re-apply the branch's changes. This resets the divergence clock but requires manual effort.
2.  Accelerate the merge: prioritize completing the branch's work and merge sooner to limit further divergence.

Neither option is free. Both cost time. The purpose of monitoring is to make the cost visible so the team can make an informed decision rather than discovering the divergence at merge time when the pressure is highest.

## The cost of abandoned branches

Abandoned branches - branches that no one is working on, no one plans to merge, and no one has deleted - impose real costs:

**Confusion for new team members.** A new developer joins the team, opens the branch list, and sees 12 branches. Which ones are active? Which are stale? Without a branch registry or naming convention that includes status, they have to ask. Or worse, they do not ask and start working on a stale branch.

**Wasted Contentstack resources.** Branches consume storage for their content type definitions and entries. While the cost per branch is modest, abandoned branches across multiple stacks add up - particularly for agencies managing many client stacks.

**False sense of progress.** A branch named feature/personalization-engine creates the impression that the personalization engine is in development. If the branch was abandoned three months ago, this impression is misleading. Stakeholders who see the branch in a status report may believe work is underway when it is not.

**Increased merge complexity for active branches.** When multiple branches exist, merge sequencing must account for all of them. Abandoned branches that no one intends to merge still occupy mental space in the planning process until someone confirms they are no longer relevant.

## Governance without over-process

Branch governance does not require heavy process. It requires visibility and accountability. A simple governance framework:

### The branch registry

A shared spreadsheet or document that tracks every active branch:

Branch name

Owner

Purpose

Created

Expected merge

Last reviewed

feature/product-catalog

Sarah Chen

New product content types

2026-01-15

2026-02-10

2026-01-29

redesign/homepage

Mike Johnson

Homepage modular blocks

2026-01-10

2026-02-20

2026-02-01

migration/article-v2

Lisa Park

Article body restructuring

2026-01-20

2026-02-12

2026-01-30

The “Last reviewed” column is key. It confirms that someone has recently verified the branch is still active and on track. A branch with a “Last reviewed” date from three months ago is a candidate for deletion.

### Weekly branch review

During the team's regular standup or weekly planning meeting, spend two minutes reviewing the branch registry:

*   Are any branches past their expected merge date?
*   Are any branches approaching the 30-day threshold?
*   Have any branches been created since the last review? If so, do they have registry entries?

### Automated branch monitoring

For teams managing multiple stacks, manual tracking does not scale. Use the Branches API to automate branch monitoring:

// List all branches and flag stale ones
async function auditBranches() {
  const response = await fetch(
    "https://api.contentstack.io/v3/stacks/branches",
    {
      headers: {
        api\_key: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_API\_KEY!,
        authorization: process.env.NEXT\_PUBLIC\_CONTENTSTACK\_MANAGEMENT\_TOKEN!,
      },
    }
  );

  const data = await response.json();
  const now = new Date();

  data.branches.forEach((branch: any) => {
    if (branch.uid === "main") return; // Skip main

    const created = new Date(branch.created\_at);
    const ageInDays = Math.floor(
      (now.getTime() - created.getTime()) / (1000 \* 60 \* 60 \* 24)
    );

    let status = "OK";
    if (ageInDays > 90) status = "STALE - consider deleting";
    else if (ageInDays > 60) status = "AT RISK - review needed";
    else if (ageInDays > 30) status = "AGING - check status";

    console.log(
      \`${branch.uid} | Age: ${ageInDays} days | Created: ${branch.created\_at} | ${status}\`
    );
  });
}

auditBranches();

This script can run as a scheduled job (via a cron job, a GitHub Actions schedule, or an Automation Hub flow if you use a webhook connector) that posts results to a Slack channel. When a branch crosses the 30-day threshold, the team is notified automatically.

## Example: quarterly cleanup at a multi-stack agency

An agency manages 10 Contentstack stacks for different clients. Each stack has its own content model, development team, and release schedule. Over a quarter, branches accumulate across all stacks as different client projects create and sometimes forget to clean up branches.

The agency's CMS architect runs a quarterly branch audit:

1.  Inventory: script queries the Branches API for all 10 stacks, listing every non-main branch with its age and creation date.
2.  Classification: branches are classified as active (owner confirms ongoing work), stale (no activity in 30+ days), or abandoned (no owner responds).
3.  Review: stale branches are compared to main to assess divergence. If the divergence is small, the branch might be worth merging. If the divergence is large and the project is deprioritized, the branch should be deleted.
4.  Action: abandoned branches are deleted after confirmation from the client stakeholder. Stale branches are either merged (if the work is complete) or deleted (if the work is no longer needed).
5.  Documentation: the branch registry is updated to reflect the current state of each stack.

In a recent quarterly audit, the architect found:

*   Stack A (retail client): 4 branches, 2 abandoned (both older than 120 days). Deleted both.
*   Stack B (media client): 6 branches, 3 stale, 1 abandoned. Merged 2 stale branches that contained completed work. Deleted the abandoned branch and the remaining stale branch after confirming the work was deprioritized.
*   Stack C (healthcare client): 3 branches, all active. No action needed.
*   Remaining stacks: 2 abandoned branches total across 7 stacks. Deleted both.

The cleanup removed 8 abandoned or stale branches, reducing confusion for developers working across multiple client stacks and eliminating the risk of someone accidentally building against a stale branch.

The quarterly cadence works for the agency model. Teams that manage a single stack with active development may need a monthly or even weekly review cadence.

## Building a branch hygiene culture

Tools and processes help, but branch hygiene ultimately depends on the team treating branches as temporary, purpose-specific tools rather than permanent features of the stack.

**Name branches with intent.** A branch named feature/product-catalog-q1-2026 communicates its purpose and expected lifespan. A branch named test communicates nothing and will likely be abandoned.

**Set a merge date when creating the branch.** Before creating a branch, state when you expect to merge it. This sets an expectation that the branch has a finite lifespan and creates accountability for meeting that deadline.

**Delete branches immediately after merging.** Do not wait for the “next cleanup.” Delete the branch as part of the merge process. Merge, verify, delete - in the same work session.

**Treat stale branches as technical debt.** An unmerged branch older than 30 days is technical debt. It represents work that is either incomplete, deprioritized, or abandoned. Like all technical debt, it accrues interest - the longer it sits, the more expensive it is to resolve.

## Common mistakes

### Mistake 1: Keeping branches “just in case”

After merging a branch, some teams keep the branch around as a backup or reference. This is unnecessary. The merge applied the branch's changes to main. The branch no longer contains unique information. If you need a backup of main's state before the merge, create a backup branch from main before merging (not after). Delete the source branch once the merge is verified.

### Mistake 2: No single person responsible for branch governance

When branch management is “everyone's responsibility,” it is no one's responsibility. Designate a specific person to own branch hygiene. This person reviews the branch list regularly, follows up with branch owners, and enforces deletion of stale branches.

### Mistake 3: Creating branches for exploratory work with no merge plan

Experimental branches - “let me try restructuring this content type” - are fine if they have a short time limit (1-2 weeks). They become problems when the experiment does not produce results but the branch is never deleted. If an experimental branch does not lead to a merge-worthy outcome within its time limit, delete it and document what you learned.

#### Key takeaways

- Connect **Avoiding branch sprawl and maintaining hygiene** back to your stack configuration before moving to the next module.
- Capture one concrete artifact (screenshot, Postman call, or code snippet) that proves the step works in your environment.
- Re-read the delivery versus management boundary for anything you changed in the entry model.

## Resources & references

| Page | Companion Markdown |
| --- | --- |
| /courses/workflow-branches-and-collaboration/workflow-and-content-lifecycle-overview | /academy/md/courses/workflow-branches-and-collaboration/workflow-and-content-lifecycle-overview.md |
| /courses/workflow-branches-and-collaboration/content-lifecycle-draft-review-publish | /academy/md/courses/workflow-branches-and-collaboration/content-lifecycle-draft-review-publish.md |
| /courses/workflow-branches-and-collaboration/designing-workflows-stages-publish-rules-and-permissions | /academy/md/courses/workflow-branches-and-collaboration/designing-workflows-stages-publish-rules-and-permissions.md |
| /courses/workflow-branches-and-collaboration/automation-hub-triggers-connectors-and-workflow-automation | /academy/md/courses/workflow-branches-and-collaboration/automation-hub-triggers-connectors-and-workflow-automation.md |
| /courses/workflow-branches-and-collaboration/branches-and-parallel-work-overview | /academy/md/courses/workflow-branches-and-collaboration/branches-and-parallel-work-overview.md |
| /courses/workflow-branches-and-collaboration/why-branches-exist-and-when-to-use-them | /academy/md/courses/workflow-branches-and-collaboration/why-branches-exist-and-when-to-use-them.md |
| /courses/workflow-branches-and-collaboration/compare-and-merge-branch-reconciliation-mechanics | /academy/md/courses/workflow-branches-and-collaboration/compare-and-merge-branch-reconciliation-mechanics.md |
| /courses/workflow-branches-and-collaboration/supporting-parallel-development-and-content-work | /academy/md/courses/workflow-branches-and-collaboration/supporting-parallel-development-and-content-work.md |
| /courses/workflow-branches-and-collaboration/avoiding-branch-sprawl-and-maintaining-hygiene | /academy/md/courses/workflow-branches-and-collaboration/avoiding-branch-sprawl-and-maintaining-hygiene.md |

## Supplement for indexing

### Content summary

Workflow, Branches, and Collaboration Learn how to scale a Contentstack implementation operationally through workflow design, automation, branching, and safer collaboration between developers and editors. Who This Course… Workflow, Branches, and Collaboration Learn how to scale a Contentstack implementation operationally through workflow design, automation, branching, and safer collaboration between developers and editors. Who This Course Is For This course is for teams that need governance without bottlenecks, especially when multiple developers, editors, or release streams are working at once. You Will Be Able To design workflow stages that support quality control and editorial velocity explain how branches support parallel schema and content work reduce release risk by coordinating people, process, and platf

### Retrieval tags

- Contentstack Academy
- workflow-branches-and-collaboration
- Workflow
- and
- Content
- Lifecycle
- Overview
- draft
- review
- publish
- Designing
- workflows
- stages
- rules

### Indexing notes

Chunk at each "### Lesson NN — Title" heading; copy lesson_id and topics from the preceding HTML comment into chunk metadata for RAG filters.
Course slug: workflow-branches-and-collaboration. Union of lesson topic tokens: Workflow, and, Content, Lifecycle, Overview, lifecycle, draft, review, publish, Designing, workflows, stages, rules, Automation, triggers, connectors, workflow, automation, Branches, Parallel, Work, Why, branches, exist, when, use, Compare, merge, branch, reconciliation, mechanics, Supporting, parallel, development, content, work, Avoiding, sprawl, maintaining, hygiene.
Do not embed or retrieve LMS-only quiz items or mastery exam answer keys from this export.

### Asset references

_No image or video thumbnail URLs were extracted._

### External links

| Label | URL |
| --- | --- |
| Contentstack Academy home | `https://www.contentstack.com/academy/` |
| Training instance setup | `https://www.contentstack.com/academy/training-instance` |
| Academy playground (GitHub) | `https://github.com/contentstack/contentstack-academy-playground` |
| Contentstack documentation | `https://www.contentstack.com/docs/` |
