Frontmatter Fetch
In Next.js you choose where data runs — getStaticProps (build time), getServerSideProps (per request), or useEffect+fetch (browser). In Astro, the frontmatter --- block IS the data layer. Top-level await fetch() there runs at build time by default, or per-request if the page opts into SSR. No useEffect, no browser fetch.
Build-time fetch: getStaticProps vs frontmatter
Section titled “Build-time fetch: getStaticProps vs frontmatter”// pages/blog.tsx (Next.js Pages Router)export async function getStaticProps() { const res = await fetch('https://api.example.com/posts'); const posts = await res.json(); return { props: { posts } };}
export default function Blog({ posts }) { return ( <ul> {posts.map(post => ( <li key={post.id}>{post.title}</li> ))} </ul> );}---// src/pages/blog.astro (Astro — static by default)const res = await fetch('https://api.example.com/posts');const posts = await res.json();---<ul> {posts.map((post) => ( <li>{post.title}</li> ))}</ul>With Astro’s default static output, this await fetch() runs once at build time — exactly like getStaticProps. The result is baked into static HTML, zero fetching at runtime.
Per-request fetch: getServerSideProps vs SSR frontmatter
Section titled “Per-request fetch: getServerSideProps vs SSR frontmatter”// pages/dashboard.tsx (Next.js Pages Router)export async function getServerSideProps(context) { const res = await fetch( `https://api.example.com/user/${context.params.id}` ); const user = await res.json(); return { props: { user } };}
export default function Dashboard({ user }) { return <h1>Hello, {user.name}</h1>;}---// src/pages/dashboard.astro (Astro SSR mode)export const prerender = false; // opt into SSR
const userId = Astro.url.searchParams.get('id');const res = await fetch(`https://api.example.com/user/${userId}`);const user = await res.json();---<h1>Hello, {user.name}</h1>export const prerender = false opts this single page into SSR — every request re-runs the frontmatter. The rest of your site stays static.
Inline data demo
Section titled “Inline data demo”---
// Swap this for: const res = await fetch('https://...'); const posts = await res.json();
const posts = [
{ id: 1, title: "Why Astro ships zero JS by default", date: "2024-01-10" },
{ id: 2, title: "Content collections vs contentlayer", date: "2024-02-03" },
{ id: 3, title: "Islands: hydrate only what you need", date: "2024-03-15" },
];
---
<html lang="en">
<head><meta charset="utf-8" /><title>Blog</title></head>
<body style="font-family:sans-serif;padding:2rem">
<h1>Latest Posts</h1>
<ul style="list-style:none;padding:0">
{posts.map((post) => (
<li style="margin:1rem 0;padding:1rem;border:1px solid #e2e8f0;border-radius:8px">
<strong>{post.title}</strong>
<span style="display:block;color:#718096;font-size:0.875rem">{post.date}</span>
</li>
))}
</ul>
</body>
</html>