How Storyblok Handles Content Versioning

Tuesday, July 1, 2025 | Storyblok CMS
Surjit

Surjit Bharath

Director of Hidden Foundry

Optimizely Most Valued Professional (OMVP), Subject Matter Expert (SME), CMS and Commerce certified

Contact Me

In this article, we’ll walk through how to build a Storyblok-powered blog that supports both preview and production environments using the same codebase. You’ll learn how to request different versions of content, see what changes between them, and understand how your frontend can cleanly handle both without needing code changes between environments.

 

Requesting Different Versions of Content

The most direct way to understand how Storyblok handles versioning is by looking at a typical content API request.

GET https://api.storyblok.com/v2/cdn/stories/{slug}?version={draft|published}&token={your_token}


Let’s break that down:

  • The slug (e.g. aeronauts) identifies the piece of content you’re fetching.

  • The version parameter controls which state of the content you want:

    • draft returns the latest saved edits (even if they’re not published).

    • published returns the last publicly published version.

  • The token determines access:

    • The preview token can fetch both draft and published versions.

    • The public token can only fetch published content.

Key takeaway: The only difference between a preview and production site is the combination of token and version used in the request.


Understanding the Response

A successful request returns a JSON object containing a story. That object holds both metadata and the custom content fields you've defined in your components.

Here’s a simplified example of a published response:

 
{
  "story": {
    "name": "My Article",
    "content": {
      "component": "blog_post",
      "title": "Aeronauts: A Journey",
      "body": "This is the article body"
    },
    "published_at": "2025-06-25T12:00:00Z",
    "uuid": "abcd-1234"
  }
}


In this response, the story.content object contains all your schema fields such as the title, body, and the component type. The published_at field shows when the content was last published, and the uuid uniquely identifies this piece of content.

Now, if you fetch the same slug using version=draft and someone has saved changes without publishing, you’ll get a response like this:

{
  "story": {
    "content": {
      "title": "Aeronauts: A Bold New Take"
    }
  }
}


That confirms what we expect: the version parameter controls whether you receive published content or work-in-progress draft content using the same URL structure.

 

Fetching Versions in Code

If you're using Vue with the official Storyblok SDK, you can programmatically request different versions like this:

Setup

First, install the Storyblok SDK:

npm install @storyblok/vue
 

Then, initialize it in your main file (e.g. main.ts or main.js):

import { StoryblokVue, apiPlugin } from '@storyblok/vue'

app.use(StoryblokVue, {
  accessToken: import.meta.env.VITE_STORYBLOK_TOKEN,
  use: [apiPlugin]
})

๐Ÿ“ You can control the version (draft or published) using an environment variable as well, e.g. VITE_STORYBLOK_VERSION.


Fetching a Single Story (e.g. in a page component)

import { useStoryblokApi } from '@storyblok/vue'

const storyblokApi = useStoryblokApi()
const { data } = await storyblokApi.get('cdn/stories/aeronauts', {
  version: import.meta.env.VITE_STORYBLOK_VERSION
})


This request will return the correct version of the aeronauts story based on your build-time environment configuration.

Fetching Multiple Stories (e.g. for a blog listing)

 

const { data } = await storyblokApi.get('cdn/stories', {
  starts_with: 'blog/',
  version: import.meta.env.VITE_STORYBLOK_VERSION
})

This will return all stories under the blog/ prefix using either the draft or published version depending on your setup.

By controlling the token and version through environment variables (.env for local/dev and platform config for deployed environments), you can cleanly support both preview and production workflows without any code changes between environments.


Summary

Storyblok makes versioning straightforward: content exists in two states draft and published and you control which one you retrieve using a query parameter and a token.

This setup enables you to support real-time previews and safe production deployments from a single codebase. Whether you're building a blog, a marketing site, or something more complex, this model gives you and your content editors a clean, reliable workflow.

Say Hello

;