Astro-Storyblok Previews Site with Netlify's Branch Deploys Feature
Tags: storyblok, astro, netlify, javascript
Published: 2023-03-20 17:45:46

---
description: This article will tell you how to set up your Astro-Storyblok projects so that your previews site deploys to a Netlify branch-deploy, while keeping your main production site in SSG mode. Bonus: Github action to keep preview branch in-sync with production.
---

**Description:** This article will tell you how to set up your Astro-Storyblok projects so that your previews site deploys to a Netlify branch-deploy, while keeping your main production site in SSG mode. Bonus: Github action to keep preview branch in-sync with production.

## Introduction

If you are using Storyblok as your headless CMS for a static site such as a blog, you might want to set up a workflow where editors can click 'save' in Storyblok, and then see their changes. This would mean setting up the visual editor to work in Storyblok, which as I explained in a [previous article](https://dev.to/sandrarodgers/getting-the-visual-editor-to-work-for-storyblok-astro-2gja), **requires your Astro project to be in SSR mode**.

What if you want to take advantage of Astro's static website mode (SSG) for your production site, but you would still like previews to work in Storyblok? How can we do this if previews require the project to be in SSR mode?

If you are using Netlify for deployments, there is a way to create an Astro project that builds the site in  **SSG mode for production environments** and **SSR mode for a previews branch** , then deploys each version to **a different Netlify URL using the Netlify branch-deploy feature**. 

You can also set up a Github action to keep the preview branch always up-to-date with any changes deployed to your main (production) branch!

Here's a walkthrough for how to set this up.

## 1. Create a branch-deploy in Netlify so you can have a special branch just for previewing content when clicking the 'save' button in Storyblok

Resource: [Netlify Branches and deploys](https://docs.netlify.com/site-deploys/overview/#branches-and-deploys)

### Create Previews Branch

In your project, create a branch off of main called `previews`. 

Go into your Netlify dashboard **Deploys -> Deploy Settings -> Branches and deploy contexts**. 
- Click **Edit Settings**. 
- Select 'Let me add individual branches' 
- In the **Additional branches** input, add your branch that you created called `previews`.

Now you have a branch that you will use for your preview environment. You're going to set up your Astro project to build in SSR mode just on this preview branch.

By the way, in Netlify terminology, a branch that you create which corresponds to a deploy that isn't from the main production branch is called a `branch-deploy`. There are different Netlify `deploy-contexts`, and `branch-deploy` is one of them (in addition to `production` and `deploy-previews`.

### Create Environment Variables

You need to make sure that you have an environment variable that tells Netlify that this branch you created is the preview environment. Later, when you go into your Astro project, you'll set up the project to build differently based on these variables.

In Netlify, go to **Deploys -> Deploy Settings -> Environment variables**. 
- Create an environment variable called `VITE_ENVIRONMENT`. 
- In the **Branch deploys**, create a variable with the value `preview`. (Of course you can name this variable differently if you prefer.)

Now Netlify can be told based on the `VITE_ENVIRONMENT` variable to either build the branch in SSG mode for production, or build it in SSR mode for the previews branch.

## 2. In the Storyblok Visual Editor settings, add your Netlify preview branch URL to the Preview URLs

Log in to your [Storyblok space](https://app.storyblok.com/). In the left side navigation menu, find **settings**. From there, navigate to **Visual Editor**.

This is where you will tell Storyblok to connect the Visual Editor to that special branch you created, the `previews` branch-deploy.

In the section **Preview URLs**, there are inputs to add multiple preview domains. Add  `previews` where it asks for **Name** and the Netlify url for that deployed previews branch where it asks for **Location**.

You can look at the Netlify URL to know which deploy-context (i.e. which branch-deploy) the preview site is building from. Since you called your branch-deploy `previews` in Netlify, you'll see something like `https://previews--NETLIFY_URL`. If you were looking at a Netlify deploy-preview, it would look like `https://deploy-preview-32--NETLIFY_URL` (where the number is the number of the deploy-preview).

## 3. Set up your `astro.config.mjs` file so that it uses conditional logic to build your site in `static` mode if its in production,  `server` mode in the preview environment

Now you'll head into your Astro project to add some necessary configuration. This is where the environment variable you set up in Netlify is going to come into play.

### Set up `.env`
In Netlify, you created the environment variable `VITE_ENVIRONMENT` with the deploy-context of **Branch deploys** being given the `preview` value.

In your project, you'll need to create a `.env` file to supply your project with that variable value so it can work in dev mode. In the `.env` file, add `VITE_ENVIRONMENT="preview"`.

### Add configuration to `astro.config.mjs`

There are four properties in the config object given to `defineConfig` that will need to be written as ternary conditionals. They are `output`, `accessToken` (in the Storyblok settings object), and `bridge` (also in Storyblok settings), and `adapter`.

For `output`, you'll give a value that is dependent on whether the deploy-context is `preview` or not. Here's how it would look:

```js
output:  import.meta.env.VITE_ENVIRONMENT  ===  "preview"  ?  "server"  :  "static",
```
This will tell the project to build in `server` mode (i.e. SSR) if it's deploying to the `preview` branch. If it's not, it will build in `static` mode (SSG).

The `integrations` array in the configuration object contains a `storyblok` method with a settings object passed in. You'll need to add ternaries for the `accessToken` and `bridge` like so:

```js
storyblok({
	accessToken:
		import.meta.env.VITE_ENVIRONMENT  ===  "preview"
		?  "HodE5R9wdAKERDFNiq7LGStl" : "UUtz6RYjUvOC0tMf1MteHQtz",
	bridge:  import.meta.env.VITE_ENVIRONMENT  ===  "preview"  ? true :  false,
	apiOptions: {
		region:  "us",
	},
	components: {
		page:  "storyblok/Page",
		feature:  "storyblok/Feature",
		grid:  "storyblok/Grid",			
		...
		},
	}),
```
This tells the Storyblok integration to use the **Preview** token if the site is deploying in SSR, and the **Public** token if the site is deploying in SSG. (These Storyblok access tokens are created in your Storyblok space in **Settings** > **Access Tokens**.)
 
In the [article](https://dev.to/sandrarodgers/getting-the-visual-editor-to-work-for-storyblok-astro-2gja) I previously referenced, which is where I show how to set up the Visual Editor, I discuss how to add the Netlify adapter. The Netlify adapter is needed for the SSR deploy-context. You can read that article for more information if you need it on setting up SSR. **You will need to set up the Netlify adapter**.

You can tell your project to use the Netlify adapter only in SSR mode:

```js
adapter: import.meta.env.VITE_ENVIRONMENT === 'preview' ? netlify() : undefined,
```

Here's an example of how the `astro.config.mjs` file might look. There might be differences depending on your project integrations, but this is a general example:

```js
import { defineConfig } from  "astro/config";
import  storyblok  from  "@storyblok/astro";
import  netlify  from  "@astrojs/netlify/functions";
import  tailwind  from  "@astrojs/tailwind";

export  default  defineConfig({
	output:  import.meta.env.VITE_ENVIRONMENT  ===  "preview"  ?  "server"  :  "static",
	adapter: import.meta.env.VITE_ENVIRONMENT === 'preview' ? netlify() : undefined,
	integrations: [
		tailwind(),
		storyblok({
			accessToken:
				import.meta.env.VITE_ENVIRONMENT  ===  "preview" ?  "HodE5R9wdAKERDFNiq7LGStl" : "UUtz6RYjUvOC0tMf1MteHQtz",
				bridge:  import.meta.env.VITE_ENVIRONMENT  ===  "preview" ? true :  false,
				apiOptions: {
				region:  "us",
				},
				components: {
					page:  "storyblok/Page",
					feature:  "storyblok/Feature",
					grid:  "storyblok/Grid",
				},
			}),
		],
});
```

## 4. Get page data from Storyblok using the public token in SSG mode, the preview token in SSR mode.

The Astro pages that pull in content data from Storyblok can pull in either `draft` content or `published` content. You need to tell your project to build the pages using `draft` content when in the `preview` deploy-context, and `published` content when in production.

For every page in your Astro **pages** folder, you will do something like this when getting data from the Storyblok API:

```js
const { data } =  await  sbApi.get("cdn/stories/home", {
	version:
		import.meta.env.VITE_ENVIRONMENT  ===  "preview"  ?  "draft"  : "published",
});
```

This will conditionally build the project using either `draft` or `published` content based on that environment variable value in Netlify.

Here is an example of a home page in an Astro project that does this:

```js
---

import { useStoryblokApi } from  "@storyblok/astro";
import  StoryblokComponent  from  "@storyblok/astro/StoryblokComponent.astro";
import  Layout  from  "../layouts/Layout.astro";

const  sbApi  =  useStoryblokApi();
const { data } =  await  sbApi.get("cdn/stories/home", {
	version:
		import.meta.env.VITE_ENVIRONMENT  ===  "preview"  ?  "draft"  : "published",
});
const  story  =  data.story;
---

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

For creating **dynamic routes**, you can use a conditional setup to tell your project to use Astro's `getStaticPaths` method in SSR mode only. Checkout this [Discord comment](https://discord.com/channels/830184174198718474/1002802280267001858/1070220357677625364) for an example by user **Nikitos**.

## 5.  Create a Github action that automatically merges any changes made to main to the previews branch too

The last thing you might want to do is to set up a continuous integration so that your preview branch stays in-sync with the main branch. That way, when there is a deploy to production, you don't have to manually update the previews branch - it will happen automatically.

You can use a Github Action to do this. Here's what you need to do.
- Create a `.github` folder in your project at the root. Inside that folder, add a `workflows` folder.
- Create a file called `auto-merge.yml` inside the `workflows` folder


![github folder structure with workflows and auto-merge.yaml file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmpbezev02m5otccwdov.png)

- Add the following code to that file:

```yaml
name: Merge main to previews
on:
	pull_request:
		branches: [main]
		types: [closed]
jobs:
	merge-main-to-previews:
	if: github.event.pull_request.merged == true
	timeout-minutes: 2
	runs-on: ubuntu-latest
	steps:
		- uses: actions/checkout@v3
		- name: Set Git config
		run: |
			git config --local user.email "actions@github.com"
			git config --local user.name "Github Actions"
		- name: Merge main to previews
		run: |
			git fetch --unshallow
			git checkout previews
			git pull
			git merge --no-ff main -m "Auto-merge main to previews"
			git push
```
Now, anytime a pull request is merged to the main (production) branch, it will also merge those changes into the previews branch!