@storyblok/api-client Reference
@storyblok/api-client is Storyblok’s modern TypeScript client for the Content Delivery API (CAPI). It exposes a single createApiClient() factory that returns resource clients for stories, links, tags, datasources, datasource entries, spaces, and experiments, with built-in caching, retry logic, and rate limiting. Responses are fully typed and can be narrowed end-to-end by passing a project schema type from @storyblok/schema to .withTypes<Schema>().
Requirements
Section titled “Requirements”- Node.js LTS (version 22.x recommended)
- Modern web browser (the latest versions of Chrome, Edge, Firefox, and Safari)
Installation
Section titled “Installation”Add the package to a project:
npm install @storyblok/api-client@alphaThe following example demonstrates how to initialize the client and fetch a story from the Content Delivery API:
import { createApiClient } from "@storyblok/api-client";
const client = createApiClient({ accessToken: process.env.STORYBLOK_ACCESS_TOKEN!, region: "eu",});
const { data, error } = await client.stories.get("home");if (error) throw error;
console.log(data?.story.content);Every resource client method returns an ApiResponse object containing data, error, response, and request. Set throwOnError: true on the client (or per request) to receive data directly and have errors thrown as ClientError instances instead.
The following sections document the createApiClient() factory, each resource client, and the exported error class and types.
createApiClient()
Section titled “createApiClient()”Accepts a configuration object and returns a client with typed methods for each Content Delivery API resource.
createApiClient(config);import { createApiClient } from "@storyblok/api-client";
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", region: "us",});createApiClient() accepts the following options:
| Option | Description |
|---|---|
accessToken |
Required. The Storyblok access token (preview or public). |
region |
The API region. Possible values: 'eu' (default), 'us', 'ap', 'ca', 'cn'. See Region. |
baseUrl |
A custom base URL that overrides the region-based URL (for example, when proxying requests). |
headers |
Additional headers to send with every request. |
throwOnError |
If true, the client throws on HTTP errors instead of returning { error }. Defaults to false. |
inlineRelations |
If true, the client replaces resolved relation UUIDs in story content with full story objects. Defaults to false. See Inline relations. |
cache |
Cache configuration object. See Caching. |
retry |
Retry configuration object. See Retry. |
rateLimit |
Rate-limiting configuration. See Rate limiting. |
timeout |
Request timeout in milliseconds. Defaults to 30_000. |
fetch |
A custom fetch implementation to use instead of the global fetch. Useful for testing or platform-specific fetch wrappers. |
The returned client exposes the following properties:
| Property | Description |
|---|---|
stories |
Methods for fetching stories. See client.stories. |
links |
Methods for fetching links. See client.links. |
spaces |
Methods for fetching space information. See client.spaces. |
datasources |
Methods for fetching datasources. See client.datasources. |
datasourceEntries |
Methods for fetching datasource entries. See client.datasourceEntries. |
tags |
Methods for fetching tags. See client.tags. |
experiments |
Methods for fetching experiments. See client.experiments. |
get |
A generic GET method for arbitrary Content Delivery API endpoints. See client.get(). |
flushCache |
Flushes the cache and resets the tracked content version. See client.flushCache(). |
interceptors |
Request, response, and error interceptors. See client.interceptors. |
withTypes |
Returns a typed client that narrows story.content to a project schema. See TypeScript. |
Region
Section titled “Region”Use the region option to match the space’s server location.
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", region: "us",});The following options are available:
| Value | Region |
|---|---|
'eu' |
European Union (default). |
'us' |
United States. |
'ap' |
Australia/Asia Pacific. |
'ca' |
Canada. |
'cn' |
China. |
client.stories
Section titled “client.stories”Use the stories resource client to retrieve stories.
client.stories.get()
Section titled “client.stories.get()”Fetches a single story by slug, ID, or UUID. A UUID identifier sets find_by: 'uuid' automatically.
client.stories.get(identifier);client.stories.get(identifier, options);// Fetch by slugconst result = await client.stories.get("blog/my-first-post", { query: { version: "draft" },});
// Fetch by IDconst result = await client.stories.get(123456);
// Fetch by UUID (find_by is set automatically)const result = await client.stories.get("2bd955a2-6e1f-4d3c-9a0d-3f1b8c7e4a56");The identifier parameter accepts the following values:
| Type | Description |
|---|---|
string |
A story’s full_slug (for example, 'blog/my-post') or uuid. A uuid sets find_by: 'uuid' automatically. |
number |
A story’s numeric id. |
The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts the following properties. For the complete list, see Query parameters in the Content Delivery API reference.
| Property | Description |
|---|---|
find_by |
Set to 'uuid' to look up a story by UUID. Set automatically for UUID identifiers. |
version |
'published' or 'draft'. |
cv |
Cache version number. |
from_release |
Retrieve content from a specific release by ID. |
resolve_links |
Resolve link fields: 'story', 'url', or 'link'. |
resolve_links_level |
Resolve link nesting depth: 1 or 2. |
resolve_relations |
Comma-separated list of component.field pairs to resolve. |
resolve_level |
Set to 2 to resolve nested stories. |
resolve_assets |
Set to 1 to include asset metadata. |
fallback_lang |
Fallback language code. |
language |
Language code for localized content. |
client.stories.list()
Section titled “client.stories.list()”Fetches multiple stories with optional filtering, sorting, and pagination.
client.stories.list();client.stories.list(options);const result = await client.stories.list({ query: { starts_with: "blog/", version: "draft", per_page: 25, },});
if (result.data) { console.log(result.data.stories);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts all properties from client.stories.get() (except find_by) plus the following. For the complete list, see Query parameters in the Content Delivery API reference.
| Property | Description |
|---|---|
starts_with |
Filter stories by path prefix. |
search_term |
Full-text search term. |
per_page |
Number of stories per page. |
page |
Page number for pagination. |
content_type |
Filter by component name. |
by_slugs |
Comma-separated list of slugs. |
excluding_slugs |
Comma-separated list of slugs to exclude. |
by_uuids |
Comma-separated list of UUIDs. |
by_uuids_ordered |
Comma-separated list of UUIDs (results preserve order). |
excluding_ids |
Comma-separated list of IDs to exclude. |
with_tag |
Filter by tag name. |
sort_by |
Sort field and direction (for example, 'published_at:desc'). |
in_workflow_stages |
Filter by workflow stage IDs. |
filter_query |
Filter query object. |
level |
Story nesting level. |
is_startpage |
Set to 1 for start pages only, 0 to exclude them. |
first_published_at_gt |
Filter by first published date (greater than). |
first_published_at_lt |
Filter by first published date (less than). |
published_at_gt |
Filter by published date (greater than). |
published_at_lt |
Filter by published date (less than). |
updated_at_gt |
Filter by updated date (greater than). |
updated_at_lt |
Filter by updated date (less than). |
excluding_fields |
Comma-separated list of fields to exclude from the response. |
client.links
Section titled “client.links”Use the links resource client to retrieve links.
client.links.list()
Section titled “client.links.list()”Fetches all links from the Content Delivery API. Useful for building site-wide navigation menus.
client.links.list();client.links.list(options);const result = await client.links.list({ query: { version: "published" },});
if (result.data) { console.log(result.data.links);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts the following properties. For the complete list, see Query parameters in the Content Delivery API reference.
| Property | Description |
|---|---|
version |
'published' or 'draft'. |
cv |
Cache version number. |
starts_with |
Filter links by path prefix. |
with_parent |
Filter by parent folder ID. |
include_dates |
Set to 1 to include date fields. |
paginated |
Set to 1 to enable pagination. |
page |
Page number. |
per_page |
Number of links per page. |
client.spaces
Section titled “client.spaces”Use the spaces resource client to retrieve information about the space.
client.spaces.get()
Section titled “client.spaces.get()”Fetches public information about the current space (name, language codes, version cv). This endpoint is never cached.
client.spaces.get();client.spaces.get(options);const result = await client.spaces.get();
if (result.data) { console.log(result.data.space);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters forwarded to the request. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
client.datasources
Section titled “client.datasources”Use the datasources resource client to retrieve datasources.
client.datasources.get()
Section titled “client.datasources.get()”Fetches a single datasource by numeric ID. Resolve the ID via client.datasources.list() if only the slug is known.
client.datasources.get(id);client.datasources.get(id, options);const result = await client.datasources.get(123);
if (result.data) { console.log(result.data.datasource);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts the following property. For the complete list, see Query parameters in the Content Delivery API reference.
| Property | Description |
|---|---|
cv |
Cache version number. |
client.datasources.list()
Section titled “client.datasources.list()”Fetches all datasources.
client.datasources.list();client.datasources.list(options);const result = await client.datasources.list({ query: { page: 1, per_page: 25 },});
if (result.data) { console.log(result.data.datasources);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts the following properties. For the complete list, see Query parameters in the Content Delivery API reference.
| Property | Description |
|---|---|
page |
Page number. |
per_page |
Number of datasources per page. |
cv |
Cache version number. |
client.datasourceEntries
Section titled “client.datasourceEntries”Use the datasourceEntries resource client to retrieve the entries of a datasource.
client.datasourceEntries.list()
Section titled “client.datasourceEntries.list()”Fetches all datasource entries.
client.datasourceEntries.list();client.datasourceEntries.list(options);const result = await client.datasourceEntries.list({ query: { datasource: "categories" },});
if (result.data) { console.log(result.data.datasource_entries);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts the following properties. For the complete list, see Query parameters in the Content Delivery API reference.
| Property | Description |
|---|---|
datasource |
The datasource slug. |
dimension |
The datasource dimension value. |
page |
Page number. |
per_page |
Number of entries per page. |
cv |
Cache version number. |
client.tags
Section titled “client.tags”Use the tags resource client to retrieve tags.
client.tags.list()
Section titled “client.tags.list()”Fetches all tags.
client.tags.list();client.tags.list(options);const result = await client.tags.list({ query: { starts_with: "blog" },});
if (result.data) { console.log(result.data.tags);}The options parameter accepts the following properties:
| Property | Description |
|---|---|
query |
Query parameters. See the table below. |
signal |
An AbortSignal for canceling the request. |
throwOnError |
Override the client-level throwOnError setting for this request. |
fetchOptions |
Custom options forwarded to the underlying fetch call. See Custom fetch options. |
The query object accepts the following properties. For the complete list, see the Tags endpoints in the Content Delivery API reference.
| Property | Description |
|---|---|
starts_with |
Filter tags by prefix. |
version |
'published' or 'draft'. |
client.experiments
Section titled “client.experiments”Use the experiments resource client to retrieve running experiments and their variant mappings.
client.experiments.list()
Section titled “client.experiments.list()”Returns all running experiments. Each experiment lists its variants and their story_mappings, which map an original_story_id/original_slug to a variant_story_id/variant_slug.
client.experiments.list();client.experiments.list(options);const result = await client.experiments.list();
if (result.data) { console.log(result.data.experiments);}The Content Delivery API has no per-story variant filter: list the experiments, pick a variant deterministically, then fetch that variant’s variant_slug via client.stories. For the underlying endpoints, refer to Experiments in the Content Delivery API reference.
client.get()
Section titled “client.get()”A generic GET method for arbitrary Content Delivery API endpoints. The caller provides the expected response type as a generic parameter.
client.get(path);client.get(path, options);const result = await client.get<{ links: Record<string, unknown> }>("/v2/cdn/links", { query: { version: "published" } });client.flushCache()
Section titled “client.flushCache()”Flushes the cache and resets the tracked content version (cv). Intended for use when cache.flush is 'manual' — for example, after receiving a Storyblok webhook.
client.flushCache();client.interceptors
Section titled “client.interceptors”The interceptors property exposes request, response, and error middleware.
client.interceptors.request.use((request, options) => { // Modify or inspect outgoing requests. return request;});
client.interceptors.response.use((response, request, options) => { // Modify or inspect incoming responses. return response;});
client.interceptors.error.use((error, response, request, options) => { // Handle or transform errors. return error;});Each interceptor channel (request, response, error) supports the following methods:
| Method | Description |
|---|---|
use(fn) |
Register an interceptor. Returns an ID. |
eject(id) |
Remove an interceptor by ID. |
exists(id) |
Check whether an interceptor is registered. |
update(id, fn) |
Replace an interceptor. |
clear() |
Remove all interceptors. |
Example: Add a custom header to every request
Section titled “Example: Add a custom header to every request”client.interceptors.request.use((request, options) => { request.headers.set("X-Custom-Header", "my-value"); return request;});ClientError
Section titled “ClientError”An error class representing an HTTP error response. Thrown when throwOnError is true, or available on the error property of the response when throwOnError is false.
import { ClientError } from "@storyblok/api-client";
new ClientError(message, { status, statusText, data });ClientError exposes the error details under a single response property:
| Property | Type | Description |
|---|---|---|
message |
string |
The error message. |
response.status |
number |
The HTTP status code. |
response.statusText |
string |
The HTTP status text. |
response.data |
ApiErrorBody | undefined |
The parsed response body (typically { error?, message? }). |
Inline relations
Section titled “Inline relations”By default, references fields remain UUID strings even when resolve_relations is used. Set inlineRelations: true to replace matching relation fields in story content with full story objects.
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", inlineRelations: true,});
const result = await client.stories.get("blog/my-post", { query: { version: "draft", resolve_relations: "article.author", },});When enabled:
- Inlining runs only for fields explicitly listed in
resolve_relations(exactcomponent.fieldmatch). - The
relsandrel_uuidsarrays remain unchanged in the response payload. - If the API response includes
rel_uuids(relation overflow), the client automatically fetches the missing related stories and includes them in the inlining pass. - Relation fields can contain either UUID strings or inlined story objects.
- Cyclic relations produce cyclic object references (for example,
A → B → A).
Before (inlineRelations: false):
result.data.story.content.author;// "9ef7f0c0-5a5f-4fbb-9f5e-1e8de56b8910"After (inlineRelations: true):
result.data.story.content.author;// { uuid: "9ef7f0c0-5a5f-4fbb-9f5e-1e8de56b8910", name: "...", ...storyFields }Caching
Section titled “Caching”The client includes a built-in in-memory cache for published (version: 'published') GET requests. Draft requests (version: 'draft') and the spaces endpoint are never cached. The default cache is an in-memory LRU (1000 entries) with the 'cache-first' strategy and a 60-second TTL.
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", cache: { strategy: "cache-first", ttlMs: 60_000, },});The cache object accepts the following options:
| Option | Description |
|---|---|
provider |
A custom cache provider. Defaults to an in-memory LRU cache (maxEntries: 1_000). See Custom cache provider. |
strategy |
A cache strategy name or custom handler function. Defaults to 'cache-first'. See Cache strategies. |
ttlMs |
Cache entry time-to-live in milliseconds. Defaults to 60_000. |
cv |
Controls the cv (content version) query parameter. 'auto' (default) attaches the tracked cv to published requests for cache busting. 'manual' omits it (the client still tracks cv internally), useful for SSR with edge caching where stable URLs are required. |
flush |
'auto' (default) flushes the cache when the API returns a new content version. 'manual' requires calling client.flushCache() explicitly. See Cache flush control. |
onRevalidationError |
Called when SWR background revalidation fails. Only relevant when strategy is 'swr'. Defaults to console.warn. |
Cache strategies
Section titled “Cache strategies”| Strategy | Behavior |
|---|---|
'cache-first' |
The default. Serve from cache if available. Fall back to the network and cache the result. |
'network-first' |
Always fetch from the network. Cache the result and fall back to cache on error. |
'swr' |
Serve stale cache immediately and revalidate in the background. If no cached response exists, the request waits for the network result. |
The strategy option also accepts a custom handler function of type CacheStrategyHandler:
import type { CacheStrategyHandler } from "@storyblok/api-client";
const customStrategy: CacheStrategyHandler = async ({ key, cachedResult, loadNetwork }) => { if (cachedResult) { return cachedResult; } return loadNetwork();};
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", cache: { strategy: customStrategy },});Cache flush control
Section titled “Cache flush control”By default (flush: 'auto'), the cache flushes automatically whenever the API returns a new content version (cv) value.
For at-scale scenarios that require external control over cache invalidation (for example, distributed Redis across multiple instances, webhook-triggered flush, or SSG build race conditions), set flush: 'manual' and call client.flushCache() explicitly.
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", cache: { flush: "manual" },});
// Flush manually after receiving a Storyblok webhookapp.post("/webhook", async (req, res) => { await client.flushCache(); res.sendStatus(200);});Custom cache provider
Section titled “Custom cache provider”Provide a custom cache provider to integrate with Redis, Memcached, or any other caching backend. The provider must implement the CacheProvider interface:
import type { CacheProvider } from "@storyblok/api-client";
const memory = new Map<string, { value: unknown; storedAt: number; ttlMs: number }>();
const customCacheProvider: CacheProvider = { async get(key) { return memory.get(key); }, async set(key, entry) { memory.set(key, { value: entry.value, storedAt: entry.storedAt ?? Date.now(), ttlMs: entry.ttlMs, }); }, async flush() { memory.clear(); },};
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", cache: { provider: customCacheProvider, strategy: "network-first", ttlMs: 30_000, },});The CacheProvider interface:
| Method | Signature | Description |
|---|---|---|
get |
(key: string) => Promise<CacheEntry | undefined> |
Retrieve a cache entry by key. |
set |
(key: string, entry: CacheEntryInput) => Promise<void> |
Store a cache entry. |
flush |
() => Promise<void> |
Remove all cache entries. |
A CacheEntry contains:
| Property | Type | Description |
|---|---|---|
value |
unknown |
The cached value. |
storedAt |
number |
Timestamp (milliseconds) when the entry was stored. |
ttlMs |
number |
Time-to-live in milliseconds. |
The client retries failed requests automatically. Pass a retry object to override individual settings — any omitted property falls back to its default.
| Property | Default | Description |
|---|---|---|
limit |
3 |
Maximum number of retry attempts. |
backoffLimit |
20_000 |
Maximum backoff delay in milliseconds. |
jitter |
true |
Add randomness to backoff delays to avoid thundering herd. |
// Increase the retry limit and keep other defaults.const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", retry: { limit: 5 },});
// Disable retries entirely.const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", retry: { limit: 0 },});Rate limiting
Section titled “Rate limiting”The client applies preventive rate limiting by default to avoid hitting the Content Delivery API limits. Refer to the rate limit documentation for more details.
The rateLimit option accepts several forms:
| Value | Behavior |
|---|---|
undefined |
The default. Auto-detect the concurrency tier from the request path and per_page query parameter. |
number |
Fixed maximum number of concurrent (in-flight) requests. |
RateLimitConfig |
Full configuration object (see below). |
false |
Disable rate limiting entirely. |
The RateLimitConfig object accepts:
| Property | Default | Description |
|---|---|---|
maxConcurrency |
Auto-detected | Fixed maximum number of concurrent (in-flight) requests. When omitted (the default), the concurrency tier is auto-detected; setting it disables auto-detection. |
adaptToServerHeaders |
true |
Dynamically adjust the concurrency limit from the X-RateLimit-Policy response header (a concurrency quota, not a request-rate limit). |
// Disable rate limiting.const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", rateLimit: false,});
// Fixed limit.const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", rateLimit: 10,});Custom fetch options
Section titled “Custom fetch options”Every resource client method accepts a fetchOptions property for passing non-standard options to the underlying fetch call. This is useful for platform-specific extensions such as Next.js cache control or Cloudflare Workers settings.
The fetchOptions object is typed as Record<string, unknown>, so any key-value pair is accepted. The options are forwarded directly to the fetch call as the second argument alongside standard RequestInit properties.
The following examples show common cases:
Next.js cache revalidation
Section titled “Next.js cache revalidation”const result = await client.stories.get("home", { fetchOptions: { next: { revalidate: 60 }, },});const result = await client.stories.list({ query: { starts_with: "blog/" }, fetchOptions: { next: { revalidate: 120, tags: ["stories"] }, },});Cloudflare Workers
Section titled “Cloudflare Workers”const result = await client.stories.get("home", { fetchOptions: { cf: { cacheTtl: 300, cacheEverything: true }, },});Custom fetch implementation
Section titled “Custom fetch implementation”The examples above forward options through the global fetch. To call the API with a different fetch altogether, supply one via the fetch config option when creating the client. Combine the fetch config option with per-request fetchOptions for full control. For example, pass Next.js fetch at init time and control revalidation per request:
import { createApiClient } from "@storyblok/api-client";
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", fetch, // Next.js extended fetch});
// This request revalidates every 60 seconds.const home = await client.stories.get("home", { fetchOptions: { next: { revalidate: 60 } },});
// This request uses on-demand revalidation via tags.const blog = await client.stories.list({ query: { starts_with: "blog/" }, fetchOptions: { next: { tags: ["blog"] } },});Error handling
Section titled “Error handling”By default, the client returns a response object with either data or error:
import { createApiClient } from "@storyblok/api-client";
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN" });
const result = await client.stories.get("home");
if (result.data) { console.log(result.data.story);} else { console.error(result.error);}Set throwOnError: true to throw a ClientError on HTTP errors instead:
import { ClientError } from "@storyblok/api-client";
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN", throwOnError: true,});
try { const result = await client.stories.get("home"); console.log(result.data.story);} catch (error) { if (error instanceof ClientError) { console.error(error.response.status, error.response.statusText, error.response.data); }}TypeScript
Section titled “TypeScript”@storyblok/api-client ships complete type definitions and is fully compatible with @storyblok/schema.
Usage with @storyblok/schema
Section titled “Usage with @storyblok/schema”Use the client in conjunction with [@storyblok/schema](/docs/libraries/js/schema) to narrow story.content to the project’s component union. The client object exposes a withTypes<T>() method that returns the same instance cast to a version that narrows story content to the components declared in the passed schema. withTypes<T>() accepts either { components: Block } or { blocks: Block }, the latter matches the Schema type produced by @storyblok/schema. It carries no runtime cost and adds no schema values to the bundle.
import { createApiClient } from "@storyblok/api-client";import type { Schema } from "./schema";
const client = createApiClient({ accessToken: "YOUR_ACCESS_TOKEN" }).withTypes<Schema>();
const { data } = await client.stories.get("home");// data.story.content is now a discriminated union of the schema's blocks.Was this page helpful?
This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.
Get in touch with the Storyblok community