← Semua pembelajaran / Astro Nol → Portal Berita
Fase 1 · Routing, Layout & Model Rendering

Statis vs on-demand — memilih model render

Astro memberimu tiga pilihan per halaman, bukan satu pilihan untuk seluruh situs. Untuk portal berita, memilih dengan benar per halaman itulah seluruh permainannya.

Sumber asli docs.astro.build Resmi Rangkuman ~9 menit baca

Intisari

  • output: "static" adalah default. Tiap halaman dirender saat build dan dilayani sebagai berkas.
  • output: "server" membalik default-nya: semua on-demand, kecuali yang kamu tandai prerender = true.
  • output: "hybrid" sudah tidak ada sejak Astro 5 — cukup server plus prerender per halaman.
  • Halaman statis tidak punya Astro.request yang berarti, dan tidak bisa membaca cookie. Ini penyebab bug "member selalu null".
  • Untuk portalmu: server + cache Cloudflare agresif mengalahkan prerender penuh, karena artikel baru langsung hidup tanpa build ulang.

Tiga model, satu tabel

Statis (prerender)On-demand (SSR)On-demand + cache CDN
Kapan direnderSaat buildTiap requestRequest pertama, lalu dari edge
Bisa baca cookieTidakYaYa, tapi merusak cache
Artikel baru munculSetelah build ulangLangsungLangsung
Beban originNolPenuhSekitar 5–10%
Waktu build 200rb artikelBerjam-jamDetikDetik
Cocok untukHalaman Tentang Kami, syarat & ketentuanDashboard member, keranjangArtikel, kategori, halaman data

Konfigurasi yang dipakai portal ini

// astro.config.mjs
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import vue from "@astrojs/vue";

export default defineConfig({
  site: "https://portal.contoh.id",
  output: "server",
  adapter: node({ mode: "standalone" }),
  integrations: [vue()],
});
---
// src/pages/tentang.astro — halaman yang tidak pernah berubah
export const prerender = true;
---

output: "hybrid" sudah dihapus. Kalau kamu menemukan tutorial yang menyuruh memakainya, tutorial itu ditulis untuk Astro 4 ke bawah. Sejak Astro 5, server plus export const prerender per halaman melakukan hal yang sama dengan lebih sedikit konsep. Beberapa hal lain di tutorial lama juga sudah berubah: <ViewTransitions /> menjadi <ClientRouter />, dan content collections wajib memakai Content Layer API.

Jebakan yang paling sering: halaman statis tidak punya request

---
// TIDAK BEKERJA di halaman prerender. Diam, tanpa error.
const sesi = Astro.cookies.get("sesi");
const member = sesi ? await ambilMember(sesi.value) : null;
---
{member ? <p>Halo, {member.nama}</p> : <a href="/masuk">Masuk</a>}

Di halaman yang di-prerender, kode ini berjalan saat build — jauh sebelum ada pembaca. Tidak ada cookie untuk dibaca, jadi member selalu null, dan setiap pembaca melihat tautan "Masuk" termasuk yang sudah login. Ia tidak melempar error; ia hanya salah.

Astro akan memperingatkanmu kalau kamu memakai API yang jelas-jelas butuh request — tapi peringatan itu mudah tenggelam di antara keluaran build lain. Yang lebih dapat diandalkan adalah kebiasaan: apa pun yang bergantung pada siapa pembacanya tidak boleh ada di halaman yang di-cache, statis maupun on-demand-yang-di-cache. Tempatnya di server island.

Kenapa on-demand + CDN, bukan prerender penuh

Untuk portal dengan 200 ribu artikel dan puluhan artikel baru per hari, prerender penuh berarti:

On-demand dengan cache edge memberi hasil yang menyerupainya dari sisi pembaca — HTML dari edge, tanpa menyentuh origin — tapi artikel baru hidup begitu editor menekan Terbitkan, dan perbaikan cukup purge satu cache tag. Ini kombinasi yang dipakai hampir semua portal berita besar, dan yang akan kita bangun di Fase 8.

Header cache yang membuatnya bekerja

---
export const prerender = false;

const artikel = await ambilArtikelPublik(Astro.params.slug!);
if (!artikel) return Astro.rewrite("/404");

// Cache di edge 5 menit, boleh disajikan basi 1 hari sambil disegarkan.
Astro.response.headers.set(
  "Cache-Control",
  "public, max-age=0, s-maxage=300, stale-while-revalidate=86400",
);
// Supaya bisa di-purge per artikel saat editor menyunting.
Astro.response.headers.set("Cache-Tag", `artikel-${artikel.id},kategori-${artikel.kategoriSlug}`);
---
ArahanUntuk siapaArtinya
max-age=0Browser pembacaJangan simpan; selalu tanya. Supaya koreksi artikel langsung terlihat.
s-maxage=300CloudflareSimpan 5 menit. Ini yang menyerap trafiknya.
stale-while-revalidate=86400CloudflareSetelah kedaluwarsa, sajikan versi lama sambil mengambil yang baru di latar. Pembaca tidak pernah menunggu origin.
Cache-TagCloudflareLabel untuk purge selektif saat artikel disunting.

stale-while-revalidate yang panjang adalah jaring pengaman produksimu. Kalau ECS tumbang, Cloudflare tetap menyajikan artikel basi selama sehari, bukan halaman error. Untuk portal berita, artikel yang terlambat lima menit jauh lebih baik daripada 502. Tambahkan stale-if-error untuk memperjelas maksudnya.

Peta keputusan untuk portalmu

HalamanModelAlasan
BerandaOn-demand, s-maxage=60Berubah sering, dibaca sangat banyak
ArtikelOn-demand, s-maxage=300 + tagJarang berubah setelah terbit; purge saat disunting
Kategori & arsipOn-demand, s-maxage=300Sama
Data perusahaanOn-demand, s-maxage=900Sumber datanya diperbarui harian
Blok paywallServer island, private, no-storePer pembaca — tidak boleh di-cache bersama
Dashboard memberOn-demand, private, no-storeSeluruh halamannya personal
Tentang, S&K, kebijakan privasiprerender = trueBerubah setahun sekali
Webhook MidtransEndpoint, tanpa cachePOST, dan tidak boleh di-cache di lapisan mana pun

Latihan: setel output: "server", lalu buat dua halaman: satu dengan prerender = true dan satu tanpa. Di kedua halaman, cetak Astro.request.headers.get("user-agent"). Jalankan pnpm build dan perhatikan bedanya di dist/ — satu jadi berkas .html, satu tidak. Lalu jalankan pnpm preview dan bandingkan apa yang tercetak di masing-masing halaman.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.