Error document is not defined muncul karena kode memanggil DOM padahal Next.js merender halaman di server. Perbaikannya bukan menambah "use client" sembarangan, melainkan memastikan baris document hanya jalan di browser lewat useEffect, event handler, atau dynamic import dengan ssr: false.
Penyebab Document Is Not Defined di App Router
App Router merender Server Component di server secara default. Objek document belum ada di sana, jadi satu baris saja cukup membuat build gagal.
- Server Component membaca
document.getElementById,document.querySelector, ataudocument.titlelangsung di body render. - Library pihak ketiga seperti editor teks, chart, date picker, atau modal mengakses DOM saat import atau render pertama.
- Kode browser ditaruh di body komponen, padahal seharusnya menunggu mount lewat
useEffectatau menunggu interaksi lewat event handler.
Tabel Diagnosis Cepat Berdasarkan Lokasi Error
Baca stack trace build, lalu cocokkan lokasinya sebelum mengubah kode.
| Gejala | Penyebab | Solusi |
|---|---|---|
Error menunjuk file page.tsx Server Component |
Akses document langsung saat prerender |
Pindah ke Client Component dan bungkus useEffect |
Error menunjuk file dengan "use client" |
document dipanggil di body render |
Tambah guard typeof document atau pindah ke effect |
Error menunjuk node_modules library UI |
Package butuh DOM saat SSR | Import dengan dynamic(..., ssr: false) |
Perbaiki Akses Document agar Hanya Jalan di Browser
Gunakan pola paling ringan dulu. Dynamic import hanya untuk library, bukan untuk satu baris document.
- Salin baris error dari log build dan cari pemanggilan
documentpersisnya. - Jika baris itu milik komponen sendiri, pindahkan komponen tersebut menjadi Client Component.
- Pindahkan pembacaan DOM ke
useEffect,useLayoutEffect, atau handler sepertionClick. - Jika penyebabnya library pihak ketiga, bungkus dengan dynamic import
ssr: false. - Jalankan ulang
npm run buildtanpa menghapus cache bila build sebelumnya belum terbukti korup.
"use client";
import { useEffect, useState } from "react";
export default function TitleReader() {
const [title, setTitle] = useState("");
useEffect(() => {
if (typeof document !== "undefined") {
setTitle(document.title);
}
}, []);
return <p>Judul halaman: {title}</p>;
}
"use client";
import dynamic from "next/dynamic";
const Editor = dynamic(() => import("./Editor"), {
ssr: false,
loading: () => <p>Memuat editor...</p>,
});
export default function Page() {
return <Editor />;
}
FAQ
Apakah use client otomatis memperbaiki error document?
Tidak. Direktif itu hanya mengizinkan browser API, pemanggilannya tetap harus menunggu mount atau interaksi.
Kapan memakai dynamic import dengan ssr false?
Pakai hanya ketika library memang membutuhkan DOM saat inisialisasi dan tidak punya mode SSR.
Kenapa error hanya muncul saat build padahal dev aman?
Mode dev kadang menunda prerender, sedangkan next build mengeksekusi semua route statis di server.