> For AI agents: the complete Sanity documentation index is available at [https://www.sanity.io/docs/llms.txt](https://www.sanity.io/docs/llms.txt).

# 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

![Video](https://stream.mux.com/BRpQTRNc2nAWQweqMyPFw5QoX7019MMOT)

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.

**npm**

```shell
# outside your studio directory
npm create astro@latest -- astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world
```

**pnpm**

```shell
# outside your studio directory
pnpm create astro@latest astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world
```

**yarn**

```shell
# outside your studio directory
yarn create astro@latest astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world
```

**bun**

```shell
# outside your studio directory
bun create astro@latest astro-hello-world --template with-tailwindcss --install --git --yes
cd astro-hello-world
```

You should now have your Studio and Astro application in two separate, adjacent folders:

**your-project-folder**

```text
├─ /astro-hello-world
└─ /studio-hello-world
```

## Install Sanity dependencies

**Run** the following inside the `astro-hello-world` directory to:

- Install and configure the official Sanity integration [@sanity/astro](https://www.sanity.io/plugins/sanity-astro)
- Install [astro-portabletext](https://github.com/theisel/astro-portabletext) to render Portable Text

**npm**

```shell
# your-project-folder/astro-hello-world
npx astro add @sanity/astro -y
npm install astro-portabletext @sanity/image-url @tailwindcss/typography
```

**pnpm**

```shell
# your-project-folder/astro-hello-world
pnpm dlx astro add @sanity/astro -y
pnpm add astro-portabletext @sanity/image-url @tailwindcss/typography
```

**yarn**

```shell
# your-project-folder/astro-hello-world
yarn dlx astro add @sanity/astro -y
yarn add astro-portabletext @sanity/image-url @tailwindcss/typography
```

**bun**

```shell
# your-project-folder/astro-hello-world
bunx astro add @sanity/astro -y
bun add astro-portabletext @sanity/image-url @tailwindcss/typography
```

## Add types for Sanity Client

**Update **`tsconfig.json` with the following additional code for TypeScript support of Sanity Client.

**/astro-hello-world/tsconfig.json**

```json
{
  // ...other settings
  "compilerOptions": {
    "types": ["@sanity/astro/module"]
  }
}

```

## Configure the Sanity client

**Update** the integration configuration to configure a Sanity Client to fetch content.

**/astro-hello-world/astro.config.mjs**

```
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](http://localhost:4321) in your browser.

**npm**

```shell
# your-project-folder/astro-hello-world
npm run dev
```

**pnpm**

```shell
# your-project-folder/astro-hello-world
pnpm run dev
```

**yarn**

```shell
# your-project-folder/astro-hello-world
yarn run dev
```

**bun**

```shell
# your-project-folder/astro-hello-world
bun run dev
```

## Display 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](http://localhost:4321/posts)

**/astro-hello-world/src/pages/posts/index.astro**

```tsx
---
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](https://github.com/tailwindlabs/tailwindcss-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.

**/astro-hello-world/src/pages/posts/[slug].astro**

```tsx
---
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 "astro-portabletext";

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">&larr; 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>
```



