Builder.io & Astro
Builder.io is a visual CMS that supports drag-and-drop content editing for building websites.
This recipe will show you how to connect your Builder space to Astro with zero client-side JavaScript.
Prerequisites
Section titled “Prerequisites”To get started, you will need to have the following:
- A Builder account and space - If you don’t have an account yet, sign up for free and create a new space. If you already have a space with Builder, feel free to use it, but you will need to modify the code to match the model name (blogpost) and custom data fields.
- A Builder API key - This public key will be used to fetch your content from Builder. Read Builder’s guide on how to find your key.
Setting up credentials
Section titled “Setting up credentials”To add your Builder API key and your Builder model name to Astro, create a .env file in the root of your project (if one does not already exist) and add the following variables:
BUILDER_API_PUBLIC_KEY=YOUR_API_KEYBUILDER_BLOGPOST_MODEL='blogpost'Now, you should be able to use this API key in your project.
At the time of writing, this key is public, so you don’t have to worry about hiding or encrypting it.
If you would like to have IntelliSense for your environment variables, you can create a env.d.ts file in the src/ directory and configure ImportMetaEnv like this:
interface ImportMetaEnv {  readonly BUILDER_API_PUBLIC_KEY: string;}Your project should now include these files:
- Directorysrc/- env.d.ts
 
- .env
- astro.config.mjs
- package.json
.env files in Astro.
Making a blog with Astro and Builder
Section titled “Making a blog with Astro and Builder”Creating a model for a blog post
Section titled “Creating a model for a blog post”The instructions below create an Astro blog using a Builder model (Type: “Section”) called blogpost that contains two required text fields: title and slug.
You can find videos showing this procedure in one of Builder’s official tutorials.
In the Builder app create the model that will represent a blog post: go to the Models tab and click the + Create Model button to create model with the following fields and values:
- Type: Section
- Name: “blogpost”
- Description: “This model is for a blog post”
In your new model use the + New Custom Field button to create 2 new fields:
- 
Text field - Name: “title”
- Required: Yes
- Default value “I forgot to give this a title”
 (leave the other parameters as their defaults) 
- 
Text field - Name: “slug”
- Required: Yes
- Default value “some-slugs-take-their-time”
 (leave the other parameters as their defaults) 
Then click the Save button in the upper right.
There are some pitfalls with the slug field:
- 
Make sure your slug is not just a number. This seems to break the fetch request to Builder’s API. 
- 
Make sure your slugs are unique, since your site’s routing will depend on that. 
Setting up the preview
Section titled “Setting up the preview”To use Builder’s visual editor, create the page src/pages/builder-preview.astro that will render the special <builder-component>:
- Directorysrc/- Directorypages/- builder-preview.astro
 
- env.d.ts
 
- .env
- astro.config.mjs
- package.json
Then add the following content:
---const builderAPIpublicKey = import.meta.env.BUILDER_API_PUBLIC_KEY;const builderModel = import.meta.env.BUILDER_BLOGPOST_MODEL;---
<html lang="en">  <head>    <title>Preview for builder.io</title>  </head>  <body>    <header>This is your header</header>
    <builder-component model={builderModel} api-key={builderAPIpublicKey}    ></builder-component>    <script async src="https://cdn.builder.io/js/webcomponents"></script>
    <footer>This is your footer</footer>  </body></html>In the above example, <builder-component> tells Builder where to insert the content from its CMS.
Setting the new route as the preview URL
Section titled “Setting the new route as the preview URL”- 
Copy the full URL of your preview, including the protocol, to your clipboard (e.g. https://{your host}/builder-preview).
- 
Go to the Models tab in your Builder space, pick the model you’ve created and paste the URL from step 1 into the Preview URL field. Make sure the URL is complete and includes the protocol, for example https://.
- 
Click the Save button in the upper right. 
When you deploy your site, change the preview URL to match your production URL, for example https://myAwesomeAstroBlog.com/builder-preview.
Testing the preview URL setup
Section titled “Testing the preview URL setup”- 
Make sure your site is live (e.g. your dev server is running) and the /builder-previewroute is working.
- 
In your Builder space under the Content tab, click on New to create a new content entry for your blogpostmodel.
- 
In the Builder editor that just opened, you should be able to see the builder-preview.astropage with a big Add Block in the middle.
Things can sometimes go wrong when setting up the preview. If something’s not right, you can try one of these things:
- Make sure the site is live - for example, your dev server is running.
- Make sure that the URLs match exactly - the one in your Astro project and the one set in the Builder app.
- Make sure it’s the full URL including the protocol, for example https://.
- If you’re working in a virtual environment like IDX, StackBlitz, or Gitpod, you might have to copy and paste the URL again when you restart your workspace, since this usually generates a new URL for your project.
For more ideas, read Builder’s troubleshooting guide.
Creating a blog post
Section titled “Creating a blog post”- 
In Builder’s visual editor, create a new content entry with the following values: - title: ‘First post, woohoo!’
- slug: ‘first-post-woohoo’
 
- 
Complete your post using the Add Block button and add a text field with some post content. 
- 
In the text field above the editor, give your entry a name. This is how it will be listed in the Builder app. 
- 
When you’re ready click the Publish button in the upper right corner. 
- 
Create as many posts as you like, ensuring that all content entries contain a titleand aslugas well as some post content.
Displaying a list of blog posts
Section titled “Displaying a list of blog posts”Add the following content to src/pages/index.astro in order to fetch and display a list of all post titles, each linking to its own page:
---
const builderAPIpublicKey = import.meta.env.BUILDER_API_PUBLIC_KEY;const builderModel = import.meta.env.BUILDER_BLOGPOST_MODEL;
const { results: posts } = await fetch(  `https://cdn.builder.io/api/v3/content/${builderModel}?${new URLSearchParams({    apiKey: builderAPIpublicKey,    fields: ["data.slug", "data.title"].join(","),    cachebust: "true",  }).toString()}`)  .then((res) => res.json())  .catch();---
<html lang="en">  <head>    <title>Blog Index</title>  </head>  <body>    <ul>      {        posts.flatMap(({ data: { slug, title } }) => (          <li>            <a href={`/posts/${slug}`}>{title}</a>          </li>        ))      }    </ul>  </body></html>