Error generateStaticParams Next.js output export: Fix
Next.js output: export error missing generateStaticParams() di dynamic route? Fix pakai halaman query-param, sudah dicek di build Next.js 16.3.5. Cek caranya.

Kalau next build berhenti dengan pesan Page "/campaigns/[id]" is missing "generateStaticParams()" so it cannot be used with "output: export" config, artinya Next.js bilang: static export nggak bisa punya route yang nilai parameternya belum diketahui saat build. Kalau ID dibuat saat runtime, daftar yang lo return dari generateStaticParams() nggak akan pernah lengkap.
Fix yang jalan untuk ID runtime: berhenti taruh ID di path. Pindahin ke query string, sajikan satu halaman statis kayak /campaigns/detail?id=42, lalu baca ID-nya di client component yang dibungkus Suspense. Semua langkah di bawah sudah gue cek di project Next.js 16.3.5 yang bersih.
Quick Fix
Ganti folder dynamic dengan folder tetap, lalu baca ID di client.
// app/campaigns/detail/CampaignDetail.tsx
"use client";
import { useSearchParams } from "next/navigation";
export default function CampaignDetail() {
const id = useSearchParams().get("id");
return <h1>Campaign {id ?? "not selected"}</h1>;
}// app/campaigns/detail/page.tsx
import { Suspense } from "react";
import CampaignDetail from "./CampaignDetail";
export default function Page() {
return (
<Suspense fallback={<p>Loading campaign...</p>}>
<CampaignDetail />
</Suspense>
);
}Hapus app/campaigns/[id], lalu link ke /campaigns/detail?id=42. Untuk kebanyakan admin dashboard, cuma segini perubahannya.
Kenapa Static Export Menolak Dynamic Route?
Static export nulis file HTML biasa saat build, jadi setiap URL harus punya file yang sudah ada. Panduan static export Next.js (gue cek ke docs v16.2.9) mencatat Dynamic Routes tanpa generateStaticParams() sebagai fitur yang nggak didukung, bareng rewrites, redirects, headers, Proxy, Server Actions, dan default image loader.
Ini output persis dari project baru dengan output: "export" dan satu file app/campaigns/[id]/page.tsx:
▲ Next.js 16.3.5 (Turbopack)
Collecting page data using 5 workers ...
> Build error occurred
Error: Page "/campaigns/[id]" is missing "generateStaticParams()" so it cannot be used with "output: export" config.Versi lama redaksinya agak beda, misalnya Page "/[[...slug]]/page" is missing exported function "generateStaticParams()", yang banyak muncul di isu GitHub. Penyebabnya sama.
Masalah kedua muncul setelah lo “menyelesaikan” error build dengan nulis beberapa ID manual. Static host kayak Cloudflare Pages menyajikan file yang cocok dengan path. Buka /campaigns/999 langsung atau refresh, file 999.html nggak ada, jadinya 404. Thread Cloudflare Community soal 404 saat buka route dynamic Next.js langsung menggambarkan persis kasus ini.
Fix 1: Halaman Query-Param (Terbaik untuk ID Runtime)
Pakai ini kalau ID datang dari database atau API, dan halamannya ada di balik login, jadi mesin pencari nggak perlu mengindeks tiap record.
Output build nunjukin hasilnya. Satu route, satu file HTML, untuk semua ID:
Route (app)
┌ ○ /
├ ○ /_not-found
└ ○ /campaigns/detail
○ (Static) prerendered as static contentout/404.html
out/campaigns/detail.html
out/index.htmlAda tiga hal penting.
Boundary Suspense itu wajib. Tanpanya build gagal dengan pesan ini, yang juga gue tangkap:
useSearchParams() should be wrapped in a suspense boundary at page "/campaigns/detail".
Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailoutDocs Next.js menjelaskan alasannya: di route yang di-prerender, useSearchParams memaksa pohon client component sampai boundary Suspense terdekat dirender di client. Yang masuk ke HTML cuma fallback-nya. Gue cek out/campaigns/detail.html dan isinya Loading campaign..., konten aslinya baru muncul setelah hydration.
Taruh hook-nya di client component kecil, seperti di Quick Fix, dan biarkan page.tsx tetap server component. Jadi cuma bagian yang butuh query string yang keluar dari prerender.
Update semua tempat yang membangun URL:
import Link from "next/link";
import { useRouter } from "next/navigation";
// list row
<Link href={{ pathname: "/campaigns/detail", query: { id: campaign.id } }}>Open</Link>;
// after creating a record
const router = useRouter();
router.push(`/campaigns/detail?id=${newId}`);Halaman edit pakai pola yang sama: /campaigns/edit?id=42. Tangani juga kasus ID kosong, karena siapa pun bisa buka /campaigns/detail tanpa id. Fallback id ?? "not selected" di atas itu minimalnya.
Fix 2: Placeholder Param Plus Rewrite Rule
Kalau URL bersih kayak /campaigns/42 wajib dipertahankan, lo bisa export satu halaman placeholder dan biarkan host menyajikannya untuk semua ID. Varian ini juga sudah gue build:
// app/campaigns/[id]/page.tsx
export async function generateStaticParams() {
return [{ id: "_" }];
}Build lolos dan cuma menulis satu file, out/campaigns/_.html. Aturan _redirects yang me-rewrite /campaigns/* ke /campaigns/_ dengan status 200 adalah pendekatan yang umum disarankan di jawaban Cloudflare Community, lalu client membaca ID asli dari usePathname(), karena params.id sudah terkunci jadi _. Untuk varian ini gue cuma jalanin build, belum deploy ke Cloudflare, jadi tes dulu rewrite-nya di preview deployment sebelum lo percaya.
Harganya: ada dua sumber kebenaran untuk routing, dipecah antara Next.js dan file khusus host. Dan bakal rusak begitu lo pindah ke host dengan sintaks rewrite berbeda.
Fix 3: Tinggalkan Static Export
Kalau lo butuh server rendering, dynamic segment beneran, atau Server Actions, static export memang bukan alat yang tepat. Perhatikan kondisi terbaru deploy ke Cloudflare, karena banyak tutorial lama sudah basi. Package @cloudflare/next-on-pages sudah deprecated dan repo GitHub-nya di-archive September 2025. Docs Cloudflare sekarang mengarahkan app Next.js ke Workers dengan adapter OpenNext, yang jalan di runtime Node.js, bukan Edge.
Itu migrasi beneran, jadi ambil jalur ini cuma kalau lo memang butuh server. Untuk dashboard ber-autentikasi yang cuma list dan edit record lewat API, static export dengan halaman query-param lebih gampang di-host dan lebih murah dijalankan. Kalau nanti lo self-host server sendiri, trade-off di Docker vs PM2 untuk Next.js di VPS: Panduan Deploy 2026 ikut berlaku.
Baca Juga: Rilis Next.js 16: Startup Lebih Cepat & Build Makin Stabil
URL Lama Setelah Refactor
Redirect yang dideklarasikan di next.config nggak jalan di static export, karena docs mencatatnya sebagai fitur yang nggak didukung. Kalau bookmark kayak /campaigns/42 harus tetap jalan, tangani di level host dengan aturan _redirects yang memetakan path lama ke URL query-param yang baru, dan verifikasi dulu di preview deploy. Untuk dashboard internal, minta tim update bookmark sering jadi jawaban paling praktis.
Gimana Gue Ketemu Masalah Ini
Gue ketemu ini di admin dashboard untuk ngelola kampanye iklan, dibangun sebagai static export dan disajikan dari Cloudflare Pages. Ada campaigns/[id] untuk halaman detail dan edit, dan ID dibuat user saat runtime. Pre-generate ID nggak mungkin, dan buka URL detail langsung bakal 404 di static host.
Gue ganti route dynamic itu dengan halaman detail dan edit berbasis query-param. Sekarang satu halaman melayani semua kampanye dan nggak ada yang perlu didaftarkan saat build. Konsekuensinya URL jadi kurang cantik, yang nggak masalah untuk halaman di balik login. Kalau lagi menimbang apa lagi yang perlu jalan di server, Server Actions vs Client Rendering di Next.js: Panduan Developer 2025 membahas pembagiannya.
Pilih Fix yang Mana?
| Opsi | URL bersih | ID runtime | Config host | Yang gue verifikasi |
|---|---|---|---|---|
| Halaman query-param | Tidak | Ya | Tidak ada | Build dan file output |
| Placeholder plus rewrite | Ya | Ya | Aturan _redirects | Build saja |
| Tinggalkan static export | Ya | Ya | Server atau Workers | Belum dites |
Pakai halaman query-param kalau ID adalah data runtime dan halamannya memang nggak dimaksudkan buat ranking di search. Pakai placeholder dan rewrite cuma kalau URL bersih itu wajib dan lo pegang konfigurasi host-nya. Tinggalkan static export kalau lo butuh server, dan rencanakan pindah ke Workers dengan OpenNext, jangan malah pakai adapter Pages yang sudah deprecated.
Baca Juga: Patch RCE Next.js 2026: Update Dulu, Baru Kunci CSP

![Astro 5 Hydration Mismatch: Penyebab dan Cara Fixnya [2026]](https://cdn.asepalazhari.com/images/articles/development/fixing-astro-hydration-mismatch-errors.jpeg)
