The ability to select both the framework and the content management system that each have the best fit with the requirements of your project, the skills of your teams, and the needs of the users and maintainers, is a great advantage when planning your technical architecture and tools for a site. What does combining tools together in a composable architecture look like? Let’s explore using Sanity, an excellent content platform, with Astro, a powerful and flexible site generator and web framework.
#TL;DR
Within this guide, we’ll go in detail explaining all the steps to discover how to develop an Astro site using Sanity as well as the process for deploying it to Netlify.
Explore the example site and repo
You can see a preview of the deployed site and the repository for the code on the following links.
- Preview: https://example-astro-sanity.netlify.app
- Repository: https://github.com/netlify/examples/
..or you can follow the steps below to create this example from the very beginning.
#Prerequisites
To follow along with all of the steps of this walk-through you’ll need:
#What is Sanity CMS?
Sanity is a headless CMS with a fully decoupled, real-time content back end and entirely customizable content workspaces.
#What is Sanity Studio?
Sanity Studio lives alongside your code and comes complete with a user interface that can be used by content editors to create, update or delete content that will be seen on your site. When you deploy your site, Sanity Studio is deployed with it.
The schema you define in your codebase using JavaScript, will determine the fields that are visible in the Sanity Studio interface and how you access these fields to display data on pages of your site.
There are a number of ways Sanity Studio can be integrated with your workflow.
- Standalone: Lives in it’s own repository
- Standalone: Lives in a directory within a mono-repo, with the site in another directory
- Standalone: Lives in its own directory within the site directory
- Embedded: Lives alongside the site code in the same directory
In this guide we’ll be using Sanity’s Astro Integration which sets Sanity Studio up as per option 4, above.
#Sanity and Astro
Astro avoids shipping any JavaScript to the client by default, and by using the sanity-astro integration you’ll be able to query data from Sanity and create static, or server-side rendered pages using Astro so that your pages are still able to be rendered without the need for client-side JavaScript.
#Getting started with Astro
To get started with Astro run the following:
If you prefer you can install Astro manually.
With an Astro site created, you can commit the changes, push to your remote repository and deploy to Netlify.
#Deploy with Netlify
Creating a new Astro site on Netlify is simple. Once you’ve logged in, you’ll be taken to https://app.netlify.com. Click “Add new site” to add a new site, follow the on-screen steps and all the default settings will be completed for you.
For more information about deploying, you can read the Get Started with Netlify guide.
It’s a good idea to deploy now as you’ll need to add some environment variables to your Netlify site configuration in a later step.
#Create a new project with the Sanity CLI
If you’re new to Sanity you’ll need to sign up and create an account before moving to the next step: Sign up to Sanity.
To create a new Sanity project run the following command in your terminal.
Select Create new project
at the prompt. You’ll then be asked to give your project and name and finally, enter Y
to use the default dataset configuration.
You should then see the following output in your terminal.
If you now head over to sanity.io/manage you’ll see your new project. Within the project’s settings you’ll find the same projectId
and the dataset
name as mentioned above.
You’ll need both of these in the next step.
#Adding environment variables using the Netlify CLI
To help prevent sensitive variables from leaking into public repositories, you can use the Netlify CLI to automatically add environment variables to both your local, and production environments without needing to create a .env file in your project.
If you already have the Netlify CLI installed, run the following in your terminal to link your local development environment with your deployed Netlify site.
A new browser window will open and you’ll be asked to authorize access.
From the prompts in the CLI select > Enter a site id, then head back over to your Netlify site configuration to find your site’s id and enter it in the CLI.
After your local environment is linked, run the following in your terminal to add both the Sanity projectId
and dataset
.
Your local environment variables can now be made safely available to your local development environment by running it via netlify dev
Tip: Control over your local dev
While developing, instead of running npm run dev
and accessing your Astro site on the default localhost port of
4321, you can run netlify dev
and access your Astro site on 8888.
When you run netlify dev
you’ll be prompted by the Netlify CLI to select a dev server to start, select the following.
#Adding Sanity Studio to Astro
To use Sanity with Astro there are two configurations. One is Sanity’s config, the other is the Sanity integration config which lives in your astro.config.mjs
, we’ll cover both in the following steps.
#Embedding Sanity Studio
Embedding Sanity Studio within your project means the config and schema will live alongside your site code and you’ll be able to access the interface via an Astro page route.
In this guide, Sanity Studio will be available at /admin
but you don’t need to create this page yourself.
You can read more about Embedding Sanity Studio in the docs.
#Install Sanity
Install the Sanity package.
#Create Sanity Config
Create a file at the root of your project and name it sanity.config.ts|js
and add the following code.
#Sanity Config Explained
The title
is the name of your project and is displayed in the Sanity Studio UI. The projectId
is the id of your Sanity project and the dataset
is the name of the data variation stored within Sanity’s content lake.
Plugins are where you can add additional tools to Sanity Studio. The structure tool is what controls the UI in Sanity Studio.
You can read more about the Structure Tool in the Sanity docs.
Schema is how you define the fields for each content type in your content model. In this example we’re creating a simple document named post, and defining two fields, one for the title which is of type string
, and one for the slug which is of type slug
.
You can read more about Schema types in the Sanity docs.
#Sanity Astro Integration
In order to run Sanity Studio as part of your Astro site, and to query data from Sanity we’ll install and use the official sanity/astro integration. The integration will automatically configure a route within your site where the Sanity Studio React SPA will be available to view.
A note about React
Whilst it’s common in Astro sites to add frameworks, in this guide you’re only adding React for Sanity Studio. Your Astro site will still ship zero JavaScript to the client
Run the following in your terminal which will install the required dependencies.
In the next step we’ll configure the Astro Sanity integration which will require access to environment variables from your astro.config.mjs
. To enable this you’ll need to install Vite.
#Astro Sanity integration configuration
As before with the sanity.config.js
, you’ll need to add the projectId
and dataset
to the integration config.
Since Sanity Studio is a React SPA running within your Astro site the output
has to be set to hybrid
which allows Astro’s compiler to include the required React client-side JavaScript on the /admin
route.
Because of this you will need to add Astro’s export const prerender = true
to any pages that you wish to render as static pages. We’ll cover this in a later step.
The studioBasePath
is used by the integration to create a route from where Sanity Studio can be viewed. In this guide, Sanity Studio is available on /admin
.
In this guide we’ll be building static pages with Astro. Setting useCdn
to false
means the integration will use Sanity’s live API which isn’t cached so your static pages will always get the freshest data.
#Add The Netlify Adapter
The final step before you can start the development server is to add Astro’s Netlify adapter.
The Netlify adapter adds a Netlify function to your project which enables server-side page rendering, in cases where your pages would benefit from being up-to-minute fresh with data.
Run the following in your terminal which will install the adapter.
And finally, update your astro.config.mjs
to import and use the Netlify adapter.
If you start the Astro dev server and visit http://localhost:8888/admin you should be looking at Sanity Studio!
Take care of CORS
The first time you visit Sanity Studio locally you’ll be prompted to add your localhost URL to Sanity’s CORS config. Click the button which will add the URL to your Sanity project.
You can go ahead and add a couple of test posts as we’ll need those next.
#Netlify Redirect
Whilst with this setup you will be able to view Sanity Studio locally, you’ll need to add a redirect so Netlify knows not to throw a 404 because there’s no actual admin.astro
file/page in the project. You can read more about avoiding 404’s in your docs: JavaScript SPAs.
Create a netlify.toml
at the root of your project and add the following code.
Notice the *
at the end of the from
route. This is a splat route and will ensure any requests made to any route that include /admin
are correctly redirected to Sanity Studio which will handle the requests like a standard React SPA.
Commit the changes and push to your remote repository.
After a successful build you’ll be able to visit Sanity Studio on your production URL at /admin
.
Take care of CORS
Just like in your local environment, the first time you visit Sanity Studio in production you’ll be prompted to add your production URL to Sanity’s CORS config.
#Update Astro Type Definitions
In the following step you’ll be querying data using the sanity:client
. To avoid TypeScript warnings add the following to your env.d.ts
.
#Content Querying with Sanity and Astro
If you haven’t already added some test posts, do that now as it’s time to query the data!
#Create a page to query data
Create a page somewhere in your site, in the sample repository we’ve added this to index.astro
but you add this to any .astro
page.
The page is set to prerender = false
, which means it will be server-side rendered. When a server-side rendered page is visited by a user, a new request is made to fetch the blog post date from Sanity. The query itself uses Sanity’s special GROQ query language.
You can read more about GROQ in the Sanity docs.
#Astro Dynamic Routes
Now that you can query data, and can create a list of links, we’ll need to create the pages for those links.
Create a new directory under src/pages
named posts
, and within the posts directory, create a new file named [slug].astro
.
This page is set to prerender = true
, and will be statically rendered. It will only ever show updated Sanity data, or make a request to the Sanity API when the site/page is rebuilt. This is achieved using Netlify and Sanity’s build/webhooks which we’ll cover next.
If you’d prefer to have this page server-side rendered you can set prerender
to false
.
There are two Sanity queries required to find the correct data for each posts page.
#The First Sanity Query
The first Sanity query runs within Astro’s getStaticPaths
function where we query all posts that have a slug. Each slug is then used to set the page’s params.slug
value.
The slug is used by Astro in the dynamic file name. E.g, [slug].astro
allowing Astro to create a page with the same name as the slug for each post returned by the Sanity query.
The slug
value can be destructured from Astro.parms
and used in the second Sanity query.
#The Second Sanity Query
The second Sanity query accepts two arguments.
- The first is the GROQ query that selects data of type “post” and checks if the value of the slug in the data is the same as the slug value destructured from
Astro.params
. - The second argument is the slug value to use in this query.
In this example we’ve destructured the title
value from the response.
Once you have data available you can return it in your HTML. In this example we display the title
in an HTML h1 element.
You can read more about dynamic routing in the Astro docs.
#Build/Webhooks
To keep your static site up to date with changes made to the CMS, a build hook or webhook can be used to trigger a rebuild whenever changes in content occur. A rebuild will regenerate any pages that are statically rendered with the latest data from Sanity.
There are two sides to the build/webhooks:
- The Netlify Build Hook (which is called by)
- The Sanity Webhook
#Netlify Build Hook
The first is on the Netlify side. Navigate to Site configuration > Continuous deployment and scroll down until you see Build hooks.
Click “Add build hook”, and give your build hook a name, then select the branch to build from.
If you like, you can read a little more detail about Netlify Build Hooks
In this example we’ve called the build hook Sanity Build Hook and have selected to build from the main branch of our repository.
When you click save you’ll be shown a URL which can be used on the Sanity side of the setup. Copy the URL and head back to Sanity Studio.
#Sanity Webhook
Navigate to API > Webhooks and fill out the fields. Give the webhook a name, then add the URL provided by Netlify. You’ll also need to select a dataset. In this example we’re using the production dataset.
With both sides now set up, go ahead and make a change to the content.
You should notice a new build with the message “Deploy triggered by hook” is now in your Netlify build queue.
#Finished
And that’s it, you now have an Astro site with Sanity Studio deployed to Netlify complete with data queries and dynamic routes with a build hook to keep static data fresh. Congrats!