Supporting parallel development and content work
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:
- 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.
- Merge branches that modify fewer content types next. Team C's article migration touches one content type. Merge it second.
- 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:
- Note the changes on your branch.
- Create a new branch from the current state of main.
- Manually apply your changes to the new branch.
- 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:
- Run a compare against main and see no conflicts (no one else modified the Article content type on main).
- Notify the content team that Article entries will gain new modular block fields.
- Deploy the frontend update that handles both old and new article formats.
- Merge migration/article-v2 to main.
- Verify the merged Article content type on main.
- Delete the migration/article-v2 branch.
Week 4: Team B completes the product catalog. They:
- 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.
- Merge feature/product-catalog to main.
- Deploy the product catalog frontend pages.
- Delete the feature/product-catalog branch.
Week 6: Team A completes the homepage redesign. They:
- 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.
- Update their branch to account for main's current state if necessary.
- Notify the content team about Homepage content type changes.
- Deploy the new homepage frontend.
- Merge redesign/homepage-modular to main.
- 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
- 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?
- 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.
- 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?