Learning Astro - Data Fetching & Server-side Rendering
Episode 6 of 24

Learning Astro - Data Fetching & Server-side Rendering

This episode covers data fetching in Astro: fetching at build time in frontmatter, integrating external APIs and the content layer, server-side rendering with an SSR adapter, and progressive and partial hydration for dynamic pages.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Content sites rarely stand alone — they often need data from external APIs, databases, or CMS services. Episode 6 covers how Astro fetches data: when data is fetched at build time, when it is fetched per request with server-side rendering (SSR), and how both modes can coexist.

The important concept you will learn is the time of data fetching. In static mode, data is fetched once at build and the result is locked into the HTML. In SSR mode, data is fetched on every request so it is always fresh. Each has trade-offs you need to understand.

This episode also introduces the Astro 5 content layer, which unifies Markdown sources, remote APIs, and databases into a single collection API.

Data Fetching at Build Time

Fetching in Frontmatter

Because frontmatter runs at build time, you can use fetch right there. Example of fetching users from an API:

JSFetch data di frontmatter
---
interface Pengguna {
  id: number;
  name: string;
}
 
const res = await fetch("https://api.contoh.dev/pengguna");
const pengguna: Pengguna[] = await res.json();
---
 
<h1>Daftar Pengguna</h1>
<ul>
  {pengguna.map((u) => <li key={u.id}>{u.name}</li>)}
</ul>

The await fetch("...") code runs once during npm run build. The resulting HTML is locked until the next build — suitable for data that rarely changes.

The getStaticPaths Pattern for Many Pages

If you want each data item to become its own page, combine it with getStaticPaths. This is analogous to getStaticProps in other frameworks: the item list is fetched once, then each item is rendered into a separate static page.

JSHalaman statis per item API
---
export async function getStaticPaths() {
  const res = await fetch("https://api.contoh.dev/artikel");
  const artikel = await res.json();
  return artikel.map((item) => ({ params: { slug: item.slug } }));
}
 
const { slug } = Astro.params;
---
 
<h1>Artikel {slug}</h1>

External API Integration and the Content Layer

The Content Layer API in Astro 5

Astro 5 introduces the content layer API, which unifies various data sources into a single collection. The collection definition is extended with a glob loader for local files or a custom loader for remote sources:

JSCollection dengan loader glob
import { defineCollection } from "astro:content";
import { glob } from "astro/loaders";
 
const blog = defineCollection({
  loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }),
});

With the content layer, getCollection("blog") stays the same, but the source can be flexible — from local files to remote APIs. Episode 11 will use this pattern for a CMS.

Handling API Errors

Build-time fetch must be resilient. If the API goes down, the build could fail. Get into the habit of checking the response status and providing a fallback:

JSFetch dengan penanganan error
const res = await fetch("https://api.contoh.dev/data");
if (!res.ok) {
  console.error("Gagal mengambil data:", res.status);
  return [];
}
const data = await res.json();

Server-Side Rendering in Astro

Enabling SSR Mode with an Adapter

For data that must always be fresh, enable server mode. First install an adapter — for example for Node.js:

Memasang adapter Node
npx astro add node

Then set the output in astro.config.mjs:

JSastro.config.mjs mode server
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
 
export default defineConfig({
  output: "server",
  adapter: node({ mode: "standalone" }),
});

With output: "server", every request is rendered on the server. .astro files can now read the request directly:

JSMembaca query parameter di SSR
---
const cari = Astro.url.searchParams.get("q") ?? "";
const res = await fetch(`https://api.contoh.dev/cari?q=${cari}`);
const hasil = await res.json();
---
 
<h1>Hasil pencarian: {cari}</h1>
<ul>
  {hasil.map((item) => <li>{item.title}</li>)}
</ul>

In the code above, Astro.url.searchParams is only available in server mode — in static mode the value is already locked at build time.

Progressive Hydration and Partial Hydration

Two Modes in One Site

Astro supports hybrid mode: static pages by default, but some pages rendered on the server. Set prerender = true in the frontmatter of static pages, or let pages render on the server. The output: "server" prop makes most pages server-rendered, and prerender = true excludes specific pages.

JSHalaman statis dalam proyek server
---
export const prerender = true;
---
 
<h1>Halaman ini tetap dibangun saat build time</h1>

When to Use Which Mode

The rule of thumb:

  • Static: content that rarely changes — articles, documentation, landing pages.
  • Server: per-user personal data, search results, pages with auth tokens.

Partial hydration in episode 7 will complete this picture: content can be fetched at any time, but JavaScript is only shipped to the interactive parts.

Info

Server mode requires a Node runtime on your hosting. For purely static hosting such as Cloudflare Pages' static tier, server pages will not run — episode 20 covers choosing the right hosting.

Conclusion

Episode 6 opens up the two ways Astro fetches data: at build time with fetch in frontmatter and getStaticPaths, and at request time with SSR mode and an adapter. The content layer API unifies local and remote data sources, and hybrid mode combines both in a single project.

The key takeaways:

  • Fetching in frontmatter runs once at build time.
  • getStaticPaths generates many static pages from one API.
  • The content layer API unifies local files and remote sources.
  • npx astro add node enables server mode with an adapter.
  • Astro.url.searchParams only works in server mode.
  • Hybrid mode combines static and server pages in one project.

In the next episode 7, we will cover interactivity and hydration: partial hydration with client:load, client:idle, and client:visible, using React, Vue, Svelte, or Solid components, and optimizing the JavaScript bundle. This is the key to keeping your site interactive without losing speed.

Learning Astro - Data Fetching & Server-side Rendering | Learning Astro