Tutorial

Cara Deploy Next.js ke Vercel

Panduan deploy Next.js ke Vercel: deploy dari Git, environment variable, ISR dan caching, memilih runtime, custom domain, serta cara menekan biaya function.

Vercel dibuat oleh tim yang sama dengan Next.js, jadi deploy-nya memang paling mulus di sini — hubungkan repositori, klik sekali, selesai. Tutorial soal itu banyak.

Yang jarang dibahas justru bagian setelahnya: kenapa tagihan atau kuota bisa membengkak, dan mode rendering mana yang sebenarnya kamu pakai. Panduan ini melewati bagian dasar dengan cepat, lalu masuk ke situ.

Yang perlu disiapkan

  • Node.js 20 atau lebih baru — cek dengan node -v.
  • Akun Vercel, paket Hobby gratis cukup untuk project pribadi.
  • Project Next.js yang jalan dengan npm run dev.
  • Repositori Git di GitHub, GitLab, atau Bitbucket.

Langkah 1: Deploy

  1. Push project-mu ke GitHub.
  2. Buka vercel.com/new, pilih repositorinya.
  3. Vercel mendeteksi Next.js otomatis. Jangan ubah setelan build apa pun.
  4. Klik Deploy.

Selesai. Situsmu live di alamat .vercel.app, dan setiap push berikutnya jadi deploy otomatis.

Jangan isi output directory

Ini kesalahan yang berulang. Orang mengisi output directory dengan .next atau out, lalu deploy menghasilkan halaman kosong. Vercel sudah tahu cara membaca keluaran Next.js. Biarkan kosong.

Alternatif: lewat CLI

npm install -g vercel
vercel login
vercel

Tambahkan --prod untuk langsung ke produksi. Praktis untuk uji cepat, tapi tidak memberimu deploy otomatis maupun preview per pull request.

Langkah 2: Environment variable

Daftarkan di Settings lalu Environment Variables. Next.js membedakan mana yang boleh sampai ke browser lewat prefiks:

// Rahasia — hanya di kode sisi server
process.env.DATABASE_URL

// Publik — ikut ter-bundle ke browser
process.env.NEXT_PUBLIC_API_URL

Apa pun yang diawali NEXT_PUBLIC_ ikut ter-bundle dan bisa dibaca siapa pun lewat DevTools. Yang tanpa prefiks hanya tersedia di Server Component, Route Handler, dan Server Action.

Vercel memisahkan nilai untuk tiga lingkungan: Production, Preview, dan Development. Manfaatkan itu — arahkan Preview ke database uji, bukan ke database produksi.

Variabel dibaca saat build

Menambahkan variabel baru tidak berpengaruh sampai kamu men-deploy ulang. Buka Deployments, pilih yang terakhir, lalu Redeploy.

Langkah 3: Pahami mana yang statis dan mana yang function

Ini bagian yang paling menentukan performa dan biaya, dan paling sering dilewati.

Next.js merender tiap rute dengan salah satu dari tiga cara, dan kamu perlu tahu rutemu masuk yang mana:

ModeKapan direnderBiaya per kunjungan
StatisSaat buildTidak ada — hanya berkas di CDN
ISRBerkala, dari cacheSesekali, saat cache kedaluwarsa
DinamisTiap permintaanSatu pemanggilan function

Setelah npm run build, Next.js mencetak tabel yang menunjukkan mode tiap rute. Baca tabel itu — di situ ketahuan kalau ada halaman yang kamu kira statis ternyata dinamis.

npm run build

Rute bertanda statis aman. Rute bertanda dinamis memanggil function tiap kali dibuka.

Penyebab tersering rute berubah jadi dinamis

Sebuah rute yang seharusnya statis akan berubah dinamis begitu kamu memakai salah satu ini di dalamnya:

  • cookies() atau headers()
  • searchParams di komponen halaman
  • fetch dengan cache: 'no-store'
  • export const dynamic = 'force-dynamic'

Sering kali pemakaiannya tidak sengaja — misalnya membaca headers() hanya untuk mendeteksi bahasa, padahal seluruh halaman jadi dinamis karenanya. Kalau begitu, pindahkan bagian itu ke Client Component supaya sisa halamannya tetap statis.

Langkah 4: ISR untuk halaman yang jarang berubah

ISR adalah jalan tengah: halaman disajikan dari cache, dan dibangun ulang secara berkala di latar belakang. Cocok untuk daftar artikel, katalog produk, atau apa pun yang berubah tapi tidak tiap detik.

// Bangun ulang paling cepat tiap 10 menit
export const revalidate = 600;

Pengunjung selalu mendapat respons instan dari cache, dan servermu hanya bekerja sesekali. Untuk situs konten, ini biasanya pilihan yang benar — bukan dinamis penuh.

Kalau kamu butuh memperbarui begitu data berubah (misalnya setelah edit di CMS), pakai revalidasi terarah dari Route Handler:

import { revalidatePath } from 'next/cache';

export async function POST() {
  revalidatePath('/blog');
  return Response.json({ ok: true });
}

Langkah 5: Pasang domain sendiri

Buka Settings lalu Domains, masukkan domainmu. Vercel menampilkan record DNS yang perlu ditambahkan — biasanya CNAME ke cname.vercel-dns.com untuk subdomain, dan A record untuk domain root.

Sertifikat SSL diterbitkan otomatis setelah DNS terverifikasi. Setelah domain aktif, pilih mana yang jadi alamat utama supaya yang satunya di-redirect 301 — jangan biarkan versi www dan non-www sama-sama menyajikan isi yang sama.

Detail DNS-nya ada di panduan custom domain dan SSL.

Langkah 6: Optimasi gambar

Komponen next/image mengubah ukuran dan format gambar secara otomatis. Di Vercel, pengubahan itu terjadi saat permintaan pertama lalu di-cache.

import Image from 'next/image';

<Image src="/foto.jpg" alt="Keterangan" width={800} height={600} />

Gambar yang dioptimasi dihitung terhadap kuota tersendiri. Kalau situsmu punya ribuan gambar unik dan lalu lintasnya ramai, ini bisa jadi pos pemakaian terbesar — lebih besar dari function. Dua cara menekannya: pakai width secukupnya (jangan minta 2000px untuk thumbnail), dan set unoptimized untuk gambar yang memang sudah kecil dan tidak perlu diproses.

Masalah yang sering muncul

Build gagal padahal jalan di lokal

Dua penyebab teratas. Pertama, kapitalisasi nama berkas — Linux membedakan Header.tsx dan header.tsx, macOS dan Windows tidak. Kedua, error TypeScript atau ESLint yang di mode dev hanya jadi peringatan, tapi menggagalkan build produksi.

Jalankan build produksi di lokal sebelum push:

npm run build

Error "Dynamic server usage"

Error: Dynamic server usage: Route couldn't be rendered statically
because it used `headers`

Kamu memakai API dinamis di rute yang seharusnya statis. Ini bukan bug — Next.js memberitahumu bahwa rute itu tidak bisa di-prerender. Kalau memang disengaja, tandai dengan export const dynamic = 'force-dynamic'. Kalau tidak, cari pemakaian cookies() atau headers() yang tidak perlu.

Halaman lama masih tampil setelah data berubah

Halaman ISR menyajikan cache sampai kedaluwarsa. Kurangi nilai revalidate, atau panggil revalidatePath() begitu data berubah.

Error 500 di produksi tapi tidak di lokal

Buka Deployments, pilih deploy terakhir, lalu tab Logs. Penyebab terbanyak: environment variable yang belum didaftarkan, sehingga kodemu mengakses properti dari undefined.

Function melebihi batas waktu

Paket Hobby membatasi durasi eksekusi function. Kalau ada rute yang memanggil API lambat, pindahkan pekerjaannya ke proses latar atau naikkan batasnya lewat konfigurasi di paket berbayar.

Batas paket Hobby

HalBatas
Bandwidth100 GB per bulan
Durasi build45 menit per build
PenggunaanNon-komersial saja
Baris terakhir itu bukan batas teknis

Paket Hobby tidak boleh dipakai untuk situs komersial — toko online, situs perusahaan, apa pun yang menghasilkan pendapatan. Tidak ada peringatan otomatis kalau kamu melanggarnya, jadi ini mudah terlewat sampai akunmu ditinjau.

Ringkasan

HalCaranya
DeployHubungkan repo di vercel.com/new
Setelan buildBiarkan bawaan, jangan diubah
Variabel publikPrefiks NEXT_PUBLIC_
Cek mode renderingBaca tabel keluaran npm run build
Halaman kontenexport const revalidate = 600

Kalau kamu mempertimbangkan platform lain, Next.js sekarang juga berjalan mulus di Cloudflare — lihat cara deploy Next.js ke Cloudflare dan perbandingannya di Cloudflare Pages vs Vercel.