Displaying content in an Astro front end
You’ve configured your Studio with a post document type and learned how to query from your hosted dataset. Before deploying the Studio, let’s query and display this content on the front-end framework of your choice.
Install a new Astro application
If you have an existing application, skip this first step and adapt the rest of the lesson to install Sanity dependencies to fetch and render content.
Run the following in a new tab or window in your Terminal (keep the Studio running) to create a new Astro application with Tailwind CSS and TypeScript.
You should now have your Studio and Astro application in two separate, adjacent folders:
# outside your studio directory
npm create astro@latest -- astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world# outside your studio directory
pnpm create astro@latest astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world# outside your studio directory
yarn create astro@latest astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world# outside your studio directory
bun create astro@latest astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world├─ /astro-hello-world
└─ /studio-hello-worldInstall Sanity dependencies
Run the following inside the astro-hello-world directory to:
- Install and configure the official Sanity integration @sanity/astro
- Install @portabletext/astro to render Portable Text
# your-project-folder/astro-hello-world
npx astro add @sanity/astro -y
npm install @portabletext/astro @sanity/image-url @tailwindcss/typography# your-project-folder/astro-hello-world
pnpm dlx astro add @sanity/astro -y
pnpm add @portabletext/astro @sanity/image-url @tailwindcss/typography# your-project-folder/astro-hello-world
yarn dlx astro add @sanity/astro -y
yarn add @portabletext/astro @sanity/image-url @tailwindcss/typography# your-project-folder/astro-hello-world
bunx astro add @sanity/astro -y
bun add @portabletext/astro @sanity/image-url @tailwindcss/typographyAdd types for Sanity Client
Update tsconfig.json with the following additional code for TypeScript support of Sanity Client.
{
// ...other settings
"compilerOptions": {
"types": ["@sanity/astro/module"]
}
}Configure the Sanity client
Update the integration configuration to configure a Sanity Client to fetch content.
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "astro/config";
import sanity from "@sanity/astro";
// https://astro.build/config
export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
integrations: [
// 👇 update these lines
sanity({
projectId: "<your-project-id>",
dataset: "<your-dataset>",
useCdn: false, // for static builds
}),
],
});Start the development server
Run the following command and open http://localhost:4321 in your browser.
# your-project-folder/astro-hello-world
npm run dev# your-project-folder/astro-hello-world
pnpm run dev# your-project-folder/astro-hello-world
yarn run dev# your-project-folder/astro-hello-world
bun run devDisplay content on a posts index page
Astro performs data fetching inside front-matter blocks (---) at the top of .astro files.
Create a route for a page with a list of posts fetched from your Sanity dataset, and visit http://localhost:4321/posts
---
import Layout from "../../layouts/main.astro";
import type { SanityDocument } from "@sanity/client";
import { sanityClient } from "sanity:client";
const POSTS_QUERY = `*[
_type == "post"
&& defined(slug.current)
]|order(publishedAt desc)[0...12]{_id, title, slug, publishedAt}`;
const posts = await sanityClient.fetch<SanityDocument[]>(POSTS_QUERY);
---
<Layout content={{ title: 'Posts' }}>
<main class="container mx-auto min-h-screen max-w-3xl p-8">
<h1 class="text-4xl font-bold mb-8">Posts</h1>
<ul class="flex flex-col gap-y-4">
{posts.map((post) => (
<li class="hover:underline">
<a href={`/posts/${post.slug.current}`}>
<h2 class="text-xl font-semibold">{post.title}</h2>
<p>{new Date(post.publishedAt).toLocaleDateString()}</p>
</a>
</li>
))}
</ul>
</main>
</Layout>Display individual posts
Create a new route for individual post pages.
The dynamic value of a slug when visiting /posts/[slug] in the URL is used as a parameter in the GROQ query used by Sanity Client.
Notice that we’re using Tailwind CSS Typography’s prose class to style the post’s body content. We installed @tailwindcss/typography in the dependencies step. Enable it by adding @plugin "@tailwindcss/typography"; to src/styles/global.css below the existing @import "tailwindcss"; line.
---
import Layout from "../../layouts/main.astro";
import type { SanityDocument } from "@sanity/client";
import { sanityClient } from "sanity:client";
import { createImageUrlBuilder, type SanityImageSource } from "@sanity/image-url";
import { PortableText } from "@portabletext/astro";
const POST_QUERY = `*[_type == "post" && slug.current == $slug][0]`;
const post = await sanityClient.fetch<SanityDocument>(POST_QUERY, Astro.params);
export async function getStaticPaths(): Promise<{ params: { slug: string } }[]> {
const SLUGS_QUERY = `*[_type == "post" && defined(slug.current)]{
"params": {"slug": slug.current}
}`;
return await sanityClient.fetch(SLUGS_QUERY);
}
const { projectId, dataset } = sanityClient.config();
const urlFor = (source: SanityImageSource) =>
projectId && dataset
? createImageUrlBuilder({ projectId, dataset }).image(source)
: null;
const postImageUrl = post.image
? urlFor(post.image)?.width(550).height(310).url()
: null;
---
<Layout content={{ title: post.title }}>
<main class="container mx-auto min-h-screen max-w-3xl p-8 flex flex-col gap-4">
<a href="/posts" class="hover:underline">← Back to posts</a>
{
postImageUrl && (
<img
src={postImageUrl}
alt={post.title}
class="aspect-video rounded-xl"
width="550"
height="310"
/>
)
}
<h1 class="text-4xl font-bold mb-8">{post.title}</h1>
<div class="prose">
<p>Published: {new Date(post.publishedAt).toLocaleDateString()}</p>
{Array.isArray(post.body) && <PortableText value={post.body} />}
</div>
</main>
</Layout>Was this page helpful?
Feedback submitted, thanks for helping us improve the docs. Have you tried these alternatives?