storyblok
The Storyblok CMS for Evolve: a module that serves the shared content contract (pages, content blocks, navigation and site layout) from a Storyblok space, so a storefront reads content the same way whichever CMS is behind it.
When to use
Use it when Storyblok is your CMS. It runs next to a commerce engine, and its
webhook flushes the page cache and publishes content-modified events when
editors publish. Each content block comes with the Terraform that provisions
its Storyblok component, and your own blocks are added the same way. Use
@evolve-framework/contentful or @evolve-framework/payload instead for
those CMSes.
Get started
Install the package with the peer dependencies it needs. It comes from the Evolve registry, which needs a one-time sign-in.
pnpm add @evolve-framework/storyblok @evolve-framework/core fastify graphql graphql-yoga zodRequirements7
@evolve-framework/core>= 1.0.0 < 2.0.0@types/node>=22optionalfastify>= 5.12.1 < 6.0.0graphql>= 16.0.0 < 17.0.0graphql-yoga>= 5.21.3 < 6.0.0msw^2.14.6 || ^3.0.1optionalzod>= 4.4.0 < 5.0.0
For example:
import { createApplication } from "@evolve-framework/core";import { cache } from "@evolve-framework/core/cache";import { NoopPublisher } from "@evolve-framework/core/messaging";import { StoryblokModule } from "@evolve-framework/storyblok";import { initContextValue } from "@evolve-framework/storyblok/graphql/context";
// Page cache โ falls back to an in-memory cache when no Redis URL is given.await cache.configure({ url: process.env.REDIS_URL });
const app = await createApplication({ name: "cms-storyblok", module: new StoryblokModule({ config: { accessToken: process.env.STORYBLOK_ACCESS_TOKEN!, managementToken: process.env.STORYBLOK_MANAGEMENT_TOKEN, spaceId: Number(process.env.STORYBLOK_SPACE_ID), categoryFolderId: Number(process.env.STORYBLOK_CATEGORY_FOLDER_ID), }, siteConfigs: [ { country: "NL", languages: ["nl", "en"] }, { country: "BE", languages: ["nl", "fr"] }, ], messagePublisher: new NoopPublisher(), webhookSecret: process.env.STORYBLOK_WEBHOOK_SECRET!, }), // Required: the module is a GraphQL module, so a context initializer must // be supplied. `initContextValue` reads the store context from the request. graphql: { context: initContextValue }, http: { address: { host: "0.0.0.0", port: 4004 } },});
await app.start();Modules
StoryblokModule
Module wiring Storyblok resolvers, typedefs and webhook into a Domain Service.
Pass either a pre-built clients bundle (from createStoryblokClients)
or a config object; the module will build its own clients from config
during init().
Only one StoryblokModule instance per process is supported -- clients are held as module-scope singletons.
import { StoryblokModule } from "@evolve-framework/storyblok";new StoryblokModule(options: StoryblokModuleOptions)| Option | Type | Description |
|---|---|---|
messagePublisher | MessagePublisher | Publisher used to emit |
webhookSecret | string | The webhook secret set on the space's webhook in Storyblok. A delivery
whose |
siteConfigs? | SiteConfig[] | Site configurations used to compute translated paths for catalog and content pages. Defaults to an empty array (no translated paths). |
origin? | string | Origin name attached to outbound |
webhookPath? | string | URL path the webhook is registered on. Defaults to "/api/webhook". |
blocks? | ContentBlockDef[] | The complete set of content blocks the module serves. Defaults to the
built-in |
mappers? | ((registry: MapperRegistry) => void) | Optional callback invoked with the pre-populated MapperRegistry. Use it to add or override mappers for custom Storyblok components. |
articlesPerProduct? | number | How many articles a product shows at most. Defaults to 4. |
siteRevalidation? | SiteRevalidationOptions | The sites whose caches a publish purges: their revalidate URLs and the
secret they share with this service. The locales purged are those of
|
clients? | StoryblokClients | Clients the module uses as they are, typically from
|
config? | StoryblokConfig | Settings the module builds its own clients from with
|
SiteConfig2The fields of siteConfigs.
| Field | Type | Description |
|---|---|---|
country | string | |
languages | string[] |
ContentBlockDef8The fields of blocks.
| Field | Type | Description |
|---|---|---|
id | string | Storyblok component name, e.g. "campaign_banner". |
typename | string | Output GraphQL typename, e.g. "CampaignBanner". |
typeDefs? | string | SDL fragment for the block's output type (+ its union membership). Omitted
for components with no GraphQL surface of their own (link wrappers such as
|
terraform? | string | Terraform provisioning the component in the Storyblok space. Omitted for a union member that is declared but not provisioned yet. |
groups? | string[] | Groups this block is a member of (which slots it can fill). |
slots? | Record<string, Slot> | Slots this block exposes (what it can contain). |
mapper? | ContentBlockMapper | Maps a Storyblok blok of this component onto the block's GraphQL type. Omitted only for blocks whose component is never mapped on its own -- pages and story singletons (assembled by their resolver) and link wrappers. |
pageMapper? | PageMapper | Maps a story of this page type onto its GraphQL page. Set only on page
types; |
StoryblokClients6The fields of clients.
| Field | Type | Description |
|---|---|---|
client | Storyblok | |
managementClient | Storyblok | |
spaceId | number | |
categoryFolderId | number | |
accessToken | string | |
defaultLanguage | string |
StoryblokConfig6The fields of config.
| Field | Type | Description |
|---|---|---|
accessToken | string | Public delivery API access token. |
spaceId | number | Storyblok space id. |
categoryFolderId | number | Parent folder id used when upserting catalog category pages. |
managementToken? | string | OAuth management token used by event handlers. |
region? | "eu" | "us" | "ap" | "ca" | "cn" | Storyblok region (defaults to "eu"). |
defaultLanguage? | string | The language whose slug a story carries as its own, with every other
language beside it as a translated slug. Defaults to MoreIt has to be the space's default language: a story's |
Extends AbstractModule<StoryblokLoaderContext>.
Testing
Test helpers in /testing. What they are for
Commands
Installing this package adds these commands to the evolve CLI.
evolve eject: Eject built-in blocks into your project so you own themevolve tf-export: Export the built-in content blocks' Terraform to disk
Entry points
@evolve-framework/storyblok | StoryblokModule, the built-in content blocks and defineContentBlock for your own, the Storyblok clients, and catalog page sync.53 exports |
@evolve-framework/storyblok/graphql/context | The request context the module's resolvers expect.3 exports |
@evolve-framework/storyblok/graphql/types | The generated GraphQL types of the content contract.237 exports |
@evolve-framework/storyblok/sbtypes | TypeScript types of the Storyblok components the module reads.44 exports |
@evolve-framework/storyblok/testing | A test context and block registry, a mocked Storyblok API and a test executor.4 exports |

