Guide

Storyblok Branches, and why they are not Git branches

The Branches app is now the Pipeline app. Here is what changed, what did not, and how to get branching on a plan that does not include it.

Last updated August 2026

If you are looking for Storyblok Branches and finding pages about Pipelines, you have not missed a deprecation. They are the same feature. Storyblok renamed the app, and the reason for the rename tells you most of what you need to know.

Why the rename happened

Storyblok’s explanation is that the name “Branches” created the wrong expectation — that these behave like Git branches. They do not, and the difference is not cosmetic.

Git branchesStoryblok branches / pipeline stages
Where you editAny branchPreview only
DirectionBidirectional — merge backOne-way, forward only
Merge conflictsExpected, resolved by handStructurally impossible
PurposeParallel developmentSequential content staging

A stage is not somewhere you work in parallel. It is a frozen destination you deploy into. Editors always work in Preview; everything downstream is read-only until a deployment pushes content forward.

The API kept the old name

This is where most confusion lands. The interface says Pipelines. The endpoint still says branches:

GET    /v1/spaces/:space_id/branches
POST   /v1/spaces/:space_id/branches
PUT    /v1/spaces/:space_id/branches/:id
DELETE /v1/spaces/:space_id/branches/:id

So a codebase can legitimately have a file called branches.ts serving a page called Pipelines. That is Storyblok’s inconsistency, not yours.

What a branch object contains

{
  "id": 12345,
  "name": "Staging",
  "space_id": 98765,
  "source_id": 12344,     // which branch this one syncs FROM
  "url": "https://staging.site.com",
  "position": 1,
  "environment": "staging",
  "deployed_at": "2026-07-30T09:12:44Z",
  "deleted_at": null
}

source_id is the important field: it defines lineage. null means the default Preview content. Everything else forms a chain rooted there.

Tokens select the branch

A delivery token can be bound to a branch_id. Your frontend then never names an environment — it holds one token, and that token is the environment. A deployment changes what the token returns without the site being redeployed or reconfigured.

POST /v1/spaces/:space_id/api_keys

{ "api_key": { "name": "Staging", "access": "public", "branch_id": 12345 } }

The trap: ids are not stable

A story’s id changes across stages. Only its uuid is stable. Any code that carries an id across a stage boundary is wrong.

This bites hardest on parent_id, relation fields and internal links, all of which are stage-local numeric references. Copy a story between stages without remapping them and you get content pointing at the wrong entry, or at nothing.

Branches are a paid add-on

The branches and deployments endpoints require the Pipelines app installed on the space. Without it, those routes are unavailable no matter how you call them — which is why so many teams end up duplicating spaces or copying stories by hand.

What stays open on every plan is /stories and /api_keys. That is enough to rebuild branching outside Storyblok, which is the approach Exacta takes: your space remains the only place anyone edits, and branches, promotion and per-branch tokens live on our side with the same API response shape.

Common questions

Are Storyblok Branches deprecated?
No. The Branches app was renamed to the Pipeline app. The feature is unchanged and the API resource is still called branches.
Can I merge a Storyblok branch back into preview?
No. Pipelines are one-way. Content flows forward from Preview into frozen stages; there is no merge back, which is why conflicts cannot occur.
How do I point my site at a specific branch?
Create a delivery token bound to that branch_id. The frontend holds that token permanently, and deployments change what it returns without any site change.
Do I need a paid plan for Storyblok branches?
The branches and deployments endpoints require the Pipelines app on the space. The stories and api_keys endpoints are available on every plan, which is what makes an external branching layer possible.
How do I track the same story across branches?
Use the uuid. Story ids are regenerated per stage, so uuid is the only identity that survives a branch boundary.

Get branches back without upgrading.

Exacta adds dev, QA and staging branches to any Storyblok plan. Content stays in Storyblok; you point your frontend at a different base URL.

Start for Free