---
title: @storyblok/astro (Version 8.x)
description: @storyblok/astro is Storyblok's official SDK for Astro applications.
url: https://www.storyblok.com/docs/libraries/js/astro-sdk
---

# @storyblok/astro (Version 8.x)

[@storyblok/astro](https://github.com/storyblok/monoblok/tree/main/packages/astro) is Storyblok’s official SDK for Astro applications.

## Requirements

-   **Astro** version 3.0 or later
-   **Node.js** LTS (version 22.x recommended)
-   **Modern web browser** (for example, Chrome, Firefox, Safari, Edge — latest versions)

## Installation

Add the package to a project by running this command in the terminal:

```bash
npm install @storyblok/astro@latest
```

## Usage

### Configuration

Import and initialize the SDK using the access token of a Storyblok space.

astro.config.mjs

```js
import { defineConfig } from "astro/config";
import { storyblok } from "@storyblok/astro";

export default defineConfig({
  integrations: [
    storyblok({
      accessToken: "YOUR_ACCESS_TOKEN",
      apiOptions: {
        region: "eu",
      },
      components: {
        page: "storyblok/Page",
        feature: "storyblok/Feature",
      },
    }),
  ],
});
```

> [!TIP]
> Learn how to retrieve an access token in the [access tokens concept](/docs/concepts/access-tokens).

> [!WARNING]
> The `region` parameter must be specified unless the space was created in the EU. Learn more in the [@storyblok/js reference](/docs/libraries/js/js-sdk).

### Components

Create an Astro component for each block defined in Storyblok and registered in the configuration. Each component will receive a `blok` prop, containing the content of the block.

src/storyblok/Feature.astro

```astro
---
import { storyblokEditable } from "@storyblok/astro";
const { blok } = Astro.props;
---

<div {...storyblokEditable(blok)}>
  <h2>{blok.headline}</h2>
</div>
```

Use `<StoryblokComponent>` to automatically render nested components (provided they are registered globally).

src/storyblok/Page.astro

```astro
---
import { storyblokEditable } from "@storyblok/astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
const { blok } = Astro.props;
---

<main {...storyblokEditable(blok)}>{blok.body?.map((blok) => <StoryblokComponent blok={blok} />)}</main>
```

### Fetching and rendering

In an Astro page or component, use the client to fetch a story and render the content using `StoryblokComponent`.

src/pages/index.astro

```astro
---
import { useStoryblokApi } from "@storyblok/astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
import BaseLayout from "../layouts/BaseLayout.astro";

const sbApi = useStoryblokApi();
const { data } = await sbApi.get("cdn/stories/home", {
  version: "draft",
  resolve_relations: ["featured-articles.posts"],
});

const story = data.story;
---

<BaseLayout>
  <StoryblokComponent blok={story.content} />
</BaseLayout>
```

## API

### `storyblok`

Import and initialize the SDK to access and configure all features.

```js
import { defineConfig } from "astro/config";
import { storyblok } from "@storyblok/astro";
export default defineConfig({
  integrations: [storyblok(OPTIONS)],
});
```

All options listed in the [@storyblok/js package reference](/docs/libraries/js/js-sdk) are available. The following additional options are available:

| Key | Description | Type |
| --- | --- | --- |
| `bridge` | Enable or disable the Storyblok Bridge. Without livePreview being enabled, the Bridge is configured to refresh on saving and publishing the story. Pass an object with Bridge options for additional configuration. See example below. | `boolean \| object` |
| `components` | Register Astro components intended to render Storyblok blocks. Located in the src directory by default. See example below. | `object` |
| `componentsDir` | Define a custom directory other than src as the location of components. | `string` |
| `livePreview` | Enable or disable live preview. Disabled by default. | `boolean` |
| `enableFallbackComponent` | Enable or disable a fallback component to be rendered if no Astro component has been defined for a Storyblok block. Disabled by default. | `boolean` |
| `customFallbackComponent` | Register a custom fallback component. Requires enableFallbackComponent to be enabled. See example below. | `string` |
| `useCustomApi` | By default, the apiPlugin from @storyblok/js is loaded. Disable this behavior by setting useCustomApi to true to optimize the final bundle when using a custom method to fetch data from Storyblok. | `boolean` |

#### Example: `components`

Register components as follows. The key represents the technical name of the Storyblok block, the value represents the location of the Astro component. The `src` folder is prepended, the `.astro` file extension is appended.

```js
storyblok({
  components: {
    page: "storyblok/Page",
    feature: "storyblok/Feature",
    grid: "storyblok/Grid",
    teaser: "storyblok/Teaser",
  },
});
```

> [!TIP]
> Components added to the `src/storyblok` folder will be automatically registered. If needed, register or override them manually using the `components` option as shown in the example above.

#### Example: `customFallbackComponent`

```js
storyblok({
  enableFallbackComponent: true,
  customFallbackComponent: "storyblok/MyCustomFallback",
});
```

#### Example: `bridge`

Learn more in the [@storyblok/preview-bridge reference](/docs/libraries/js/preview-bridge). Note that `resolveRelations` and `resolveLinks` only become effective when `livePreview` is enabled.

```js
storyblok({
  bridge: {
    customParent: "iframe-container",
    preventClicks: true, // Defaults to false.
    resolveRelations: ["article.author"],
    resolveLinks: "story",
  },
});
```

### `useStoryblokApi`

`useStoryblokApi()` returns the client instantiated in the application.

```astro
---
import { useStoryblokApi } from "@storyblok/astro";
const storyblokApi = useStoryblokApi();
const { data } = await storyblokApi.get(URL, API_OPTIONS);
---
```

For the `API_OPTIONS`, see the [storyblok-js-client reference](https://github.com/storyblok/monoblok/tree/main/packages/js-client).

### `storyblokApi`

The `storyblokApi` client provides direct access to the Storyblok API.

> [!NOTE]
> Unlike `useStoryblokApi`, which is limited to the Astro page or component context, `storyblokApi` can be used anywhere in the application (in pages, API routes, utility functions, and more). This is useful when Storyblok data needs to be fetched outside of Astro’s rendering context.

```js
import { storyblokApi } from "@storyblok/astro/client";

const { data } = await storyblokApi.get("cdn/stories/home", {
  version: "draft",
});
```

### `getLiveStory`

_Deprecated since_ (8.2.0)

> [!WARNING]
> `getLiveStory` is deprecated and will be removed in a future release. Use `getPayload` for a more flexible and powerful live preview experience.

`getLiveStory` returns the updated story object whenever changes are made in the Storyblok Visual Editor, providing a real-time editing experience. Requires `livePreview` to be enabled.

```js
await getLiveStory(Astro);
```

### `getPayload`

`getPayload` provides access to live preview data, including the story and any custom server-side data. Requires `livePreview` to be enabled.

It enables:

-   Access to live preview story data
-   Passing and reusing server-side data during preview
-   Avoiding unnecessary refetching of external resources

> [!NOTE]
> See the [live preview](#live-preview) section for further tips and best practices to optimize the experience when using `getPayload`.

#### Example: `getPayload`

```astro
---
import { getPayload, useStoryblokApi } from "@storyblok/astro";
import StoryblokComponent from "@storyblok/astro/StoryblokComponent.astro";
import StoryblokServerData from "@storyblok/astro/StoryblokServerData.astro";
import { getUsers, type User } from "src/lib/getUsers";

interface ServerData {
  users?: User[];
}

interface MyStory extends ISbStoryData {
  content: { myField: string };
}
const { slug } = Astro.params;
const payload = await getPayload<ServerData, MyStory>({
  locals: Astro.locals,
});

// Use live preview data or fallback to API
const story =
  payload?.story ??
  (
    await storyblokApi.get(`cdn/stories/${slug || "home"}`, {
      version: "draft",
      resolve_relations: ["featured-articles.posts"],
    })
  ).data.story;

const users = payload?.serverData?.users ?? (await getUsers());
---

<p>{users?.length} users loaded.</p>
<StoryblokComponent blok={story.content} />
<StoryblokServerData users={users} />
```

### `StoryblokServerData`

`StoryblokServerData` allows for providing pre-fetched server-side data to the live preview environment.

This is useful when an application depends on external data sources (for example, APIs, databases) that are slow or expensive to fetch repeatedly. The data is sent once and reused during live preview updates.

```astro
<StoryblokServerData users={users} />
```

### `StoryblokComponent`

This component automatically renders Storyblok blocks for corresponding Astro components registered using the `components` option of the `storyblok` Astro integration. It requires a `blok` property. Any additional passed properties are forwarded to the Astro component.

```jsx
<StoryblokComponent blok={story.content} />
```

Use it to iterate over blocks fields as follows:

```jsx
{
  blok.nested_bloks?.map((currentBlok) => <StoryblokComponent blok={currentBlok} />);
}
```

### `storyblokEditable`

This function connects Astro components to their Storyblok counterparts, adding HTML attributes that allow the Storyblok Bridge to work. See the [@storyblok/js reference](/docs/libraries/js/js-sdk) for further details.

```astro
---
import { storyblokEditable } from "@storyblok/astro";

const { blok } = Astro.props;
---

<section {...storyblokEditable(blok)}>{blok.title}</section>
```

## Live preview

### Events

Use these events to hook into the live preview rendering lifecycle:

-   `storyblok-live-preview-updating`: Triggered when a live preview update starts (before the DOM is updated).
-   `storyblok-live-preview-updated`: Triggered after the DOM has been updated.

```js
<script>
  document.addEventListener("storyblok-live-preview-updating", () => {
    console.log("Storyblok live preview: DOM updating");
  });

  document.addEventListener("storyblok-live-preview-updated", () => {
    console.log("Storyblok live preview: DOM updated");
  });
</script>
```

### Preserve component state

Use the `data-preserve-state` attribute to prevent parts of the UI from re-rendering during live preview updates.

```html
<div data-preserve-state></div>
```

### Disable live preview per route

Use the `storyblok-live-preview` meta tag to disable live preview for specific routes.

```html
<meta name="storyblok-live-preview" content="disabled" />
```

### Editor-controlled updates

Use the `storyblok-live-preview-updating` event to listen to live preview update events and control rendering behavior:

```js
document.addEventListener("storyblok-live-preview-updating", (event) => {
  event.preventDefault();
});
```

### `StoryblokRichText`

Used to render a rich text field from a Storyblok story.

```astro
<StoryblokRichText document={blok.richtext_field} />
```

The component accepts the following optional props:

-   `components`: Allows custom Astro components to be provided for supported rich text nodes and marks.
-   `optimizeImage`: Allows image optimization options to be configured for image nodes.

> [!TIP]
> When using TypeScript, custom components are fully type-safe through the `SbAstroRichTextProps<T>` utility type. For example, `SbAstroRichTextProps<"link">` provides access to the attributes available for the `link` mark, while `SbAstroRichTextProps<"heading">` provides access to heading-specific attributes such as `level`.

See the [@storyblok/richtext reference](/docs/libraries/js/rich-text) for a complete list of supported nodes, marks, and customization options.

#### Custom components

Custom components can be registered using the `components` prop. The key must match a supported rich text node or mark name.

```ts
import type { SbAstroRichTextComponentMap } from "@storyblok/astro";

const components: SbAstroRichTextComponentMap = {
  heading: CustomHeading,
  link: CustomLink,
  table: CustomTable,
};
```

The components can then be passed to `StoryblokRichText`:

```astro
<StoryblokRichText document={blok.richtext_field} components={components} />
```

#### Example: Custom link component (mark)

Marks receive their rendered child content through Astro’s `<slot />`.

```astro
---
import type { SbAstroRichTextProps } from "@storyblok/astro";

type Props = SbAstroRichTextProps<"link">;

const { attrs } = Astro.props;
---

<a href={attrs?.href ?? ""} target={attrs?.target ?? "_self"}>
  <slot />
</a>
```

#### Example: Custom heading component (node)

Nodes can use Astro’s `<slot />` to pass through child content that has already been rendered.

```astro
---
import type { SbAstroRichTextProps } from "@storyblok/astro";
type Props = SbAstroRichTextProps<"heading">;

const { attrs } = Astro.props;

const Tag = `h${attrs?.level ?? 1}`;
---

<Tag class="custom-heading">
  <slot />
</Tag>
```

#### Example: Custom table component (advanced node)

For advanced use cases, nodes can access `content` and `context` to recursively render child nodes using `StoryblokRichText`.

The `splitTableRows` utility can be used to separate table header rows from body rows when creating custom table components.

```astro
---
import { splitTableRows, type SbAstroRichTextProps } from "@storyblok/astro";
import StoryblokRichText from "@storyblok/astro/StoryblokRichText.astro";
type Props = SbAstroRichTextProps<"table">;

const { content, context } = Astro.props;

const { headerRows, bodyRows } = splitTableRows(content);
---

<table class="custom-table">
  {
    headerRows && (
      <thead>
        <StoryblokRichText document={headerRows} {...context} />
      </thead>
    )
  }

  <tbody>
    <StoryblokRichText document={bodyRows} {...context} />
  </tbody>
</table>
```

### Utility helpers

The Astro SDK also exports the core rich text utilities from `@storyblok/richtext`. These can be useful when implementing advanced custom components, such as custom image or table rendering.

Available utilities include:

-   `renderRichText`: The core rich text rendering function.
-   `buildStoryblokImage`: Generates optimized Storyblok Image Service URLs.
-   `splitTableRows`: Splits table rows into `headerRows` and `bodyRows`.

## Further resources

[Repository Playground](https://github.com/storyblok/monoblok/tree/main/packages/astro/playground)See the repository playground for additional examples.

[storyblok-rich-text-astro-renderer by NordSecurity](https://github.com/NordSecurity/storyblok-rich-text-astro-renderer)Rich text renderer package for advanced functionality, including the rendering of native Astro components for nested rich text blocks.

[Astro Guide](/docs/guides/astro/)See the Astro guide for a comprehensive walkthrough on integrating Storyblok with Astro.

[Space Blueprint: Astro](https://github.com/storyblok/blueprint-core-astro)See the core space blueprint for Astro to kickstart a new project.

## Previous versions

[@storyblok/astro (Version 7.x)](/docs/libraries/js/astro-sdk/v7)

## Pagination

-   [Previous: React SDK](/docs/libraries/js/react-sdk)
-   [Next: Nuxt SDK](/docs/libraries/js/nuxt-sdk)
