Tutorial

Cara Deploy Nuxt ke Vercel

Panduan deploy aplikasi Nuxt ke Vercel: preset Nitro, mode rendering per rute, ISR, runtimeConfig untuk environment variable, dan solusi error yang sering muncul.

Deploy Nuxt ke Vercel praktis tanpa konfigurasi. Nitro — mesin server di balik Nuxt — mendeteksi Vercel otomatis dan menyiapkan keluaran yang sesuai. Kamu hubungkan repositori, klik deploy, selesai.

Yang menarik justru bagian setelahnya: Nuxt membiarkan kamu menentukan mode rendering per rute. Itu fitur yang jarang dipakai orang padahal dampaknya besar untuk kecepatan dan biaya. Panduan ini membahas deploy dasarnya dulu, lalu bagian itu.

Yang perlu disiapkan

  • Node.js 20 atau lebih baru — cek dengan node -v.
  • Akun Vercel, paket Hobby gratis cukup.
  • Project Nuxt yang jalan dengan npm run dev. Belum ada? npx nuxi@latest init app-saya.
  • Repositori Git di GitHub, GitLab, atau Bitbucket.

Langkah 1: Deploy

Serius, ini saja:

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

Nitro melihat variabel lingkungan VERCEL saat build, lalu memilih preset vercel sendiri. Hasilnya ditulis ke .vercel/output dalam format yang langsung dimengerti Vercel.

Kalau kamu mau eksplisit — misalnya supaya build lokal berperilaku sama — set preset di nuxt.config.ts:

export default defineNuxtConfig({
  nitro: {
    preset: 'vercel'
  }
});
Jangan set output directory di dashboard

Ini kesalahan yang sering terjadi. Orang mengisi output directory dengan dist atau .output, lalu deploy gagal atau menghasilkan halaman kosong. Preset Vercel memakai .vercel/output, dan Vercel sudah tahu itu. Biarkan kosong.

Langkah 2: Pilih mode rendering per rute

Di sinilah Nuxt jadi menarik. Lewat routeRules, kamu bisa memberi tiap bagian situs perlakuan berbeda — tanpa memecah project.

export default defineNuxtConfig({
  routeRules: {
    // Halaman depan: dirender saat build, disajikan sebagai HTML statis
    '/': { prerender: true },

    // Blog: dibangun ulang tiap 10 menit
    '/blog/**': { isr: 600 },

    // Dasbor: selalu dirender per permintaan, jangan di-cache
    '/dasbor/**': { ssr: true, cache: false },

    // Halaman admin: aplikasi sisi klien saja
    '/admin/**': { ssr: false },

    // Redirect permanen
    '/artikel-lama': { redirect: { to: '/blog', statusCode: 301 } }
  }
});

Empat mode yang tersedia:

AturanKapan direnderCocok untuk
prerender: trueSaat buildHalaman depan, tentang, dokumentasi
isr: 600Berkala, dari cacheBlog, katalog produk
ssr: trueTiap permintaanHalaman yang butuh data pengguna
ssr: falseDi browserDasbor di balik login

Aturan praktisnya: prerender sebanyak mungkin. Halaman yang dirender saat build tidak memanggil function sama sekali — lebih cepat untuk pengunjung, dan tidak menghabiskan kuota.

Langkah 3: Environment variable

Nuxt memakai runtimeConfig, dan pembagiannya sederhana: apa pun di dalam public ikut ke browser, sisanya hanya di server.

export default defineNuxtConfig({
  runtimeConfig: {
    // Hanya server
    apiSecret: '',

    // Ikut ke browser
    public: {
      apiBase: 'https://api.situsku.com'
    }
  }
});

Nilainya diisi lewat environment variable dengan pola penamaan tertentu. apiSecret diisi oleh NUXT_API_SECRET, dan public.apiBase diisi oleh NUXT_PUBLIC_API_BASE.

Daftarkan nilainya di dashboard Vercel lewat Settings → Environment Variables. Memakainya di kode:

const config = useRuntimeConfig();

// Di komponen — hanya yang public yang tersedia
const base = config.public.apiBase;

// Di server route — semuanya tersedia
const secret = config.apiSecret;
Jangan pakai process.env langsung di komponen

Nilainya akan undefined di browser. Selalu lewat useRuntimeConfig() — itu satu-satunya cara yang bekerja konsisten di server dan klien.

Langkah 4: Pasang domain sendiri

Buka project di dashboard Vercel → SettingsDomains → masukkan domainmu. Vercel menampilkan record DNS yang perlu ditambahkan, dan menerbitkan sertifikat SSL otomatis setelah terverifikasi.

Setelah domain aktif, isi site atau base URL di konfigurasimu supaya sitemap dan URL kanonik menunjuk ke alamat yang benar. Langkah DNS lengkapnya ada di panduan custom domain dan SSL.

Masalah yang sering muncul

Halaman kosong setelah deploy

Hampir selalu karena output directory diisi manual di dashboard. Kosongkan lagi, lalu redeploy.

Error "500 Internal Server Error" di semua halaman

Buka log function di dashboard Vercel — biasanya ada runtimeConfig yang dipakai tapi nilainya belum didaftarkan, jadi kodemu mengakses properti dari undefined. Cek juga penamaan variabelnya sudah mengikuti pola NUXT_.

Error hydration mismatch

Hydration completed but contained mismatches

HTML dari server berbeda dari yang dirender browser. Penyebab tersering: menampilkan tanggal atau waktu yang dihitung saat render, atau nilai acak. Bungkus bagian itu dengan <ClientOnly>:

<ClientOnly>
  <p>{{ new Date().toLocaleString() }}</p>
</ClientOnly>

Prerender gagal untuk rute dinamis

Kalau rutenya seperti /blog/[slug], Nitro perlu tahu daftar slug-nya. Beri tahu lewat nitro.prerender.routes, atau pastikan semua halaman itu tertaut dari halaman yang ikut di-prerender — crawler Nitro akan mengikutinya sendiri.

  nitro: {
    prerender: {
      crawlLinks: true,
      routes: ['/blog/artikel-pertama']
    }
  }

Build melebihi batas waktu

Kalau kamu mem-prerender ratusan halaman, build bisa panjang. Kurangi cakupan prerender, atau pindahkan sebagian ke isr — halaman dibangun saat pertama diminta, bukan semuanya saat build.

Memastikan deploy-nya benar

Setelah deploy pertama, periksa tiga hal ini sebelum menganggap selesai:

  1. Lihat mana yang statis dan mana yang function. Di dashboard Vercel, buka tab Deployments, pilih deploy terakhir, lalu Source. Halaman yang di-prerender muncul sebagai berkas HTML; sisanya dilayani function.
  2. Cek header respons. Halaman yang di-cache mengembalikan header x-vercel-cache berisi HIT pada permintaan kedua.
  3. Buka log function. Kalau ada rute yang error, log-nya muncul di sana lengkap dengan stack trace.
curl -sSI https://situsku.vercel.app/ | grep -i "x-vercel"

Kenapa prerender menghemat uang

Setiap halaman yang dirender per permintaan memanggil serverless function, dan panggilan itu dihitung terhadap kuota. Halaman yang di-prerender tidak memanggil apa pun — ia hanya berkas statis di CDN.

Untuk situs dengan lalu lintas ramai, selisihnya besar. Satu halaman depan yang tidak di-prerender bisa menghabiskan kuota function lebih banyak daripada seluruh sisa situsmu digabung.

Aturan praktis

Tanyakan satu hal untuk tiap halaman: apakah isinya berbeda untuk dua orang berbeda pada saat yang sama? Kalau tidak, halaman itu seharusnya prerender atau isr — bukan ssr.

Batas paket Hobby Vercel

HalBatas
Bandwidth100 GB per bulan
Durasi build45 menit per build
PenggunaanNon-komersial saja
Yang paling sering terlewat

Paket Hobby tidak boleh dipakai untuk situs komersial. Toko online, situs perusahaan, atau apa pun yang menghasilkan pendapatan harus di paket berbayar. Ini ketentuan penggunaan, bukan batas teknis — jadi tidak ada peringatan apa pun sampai akunmu ditinjau.

Ringkasan

HalCaranya
DeployHubungkan repo di vercel.com/new, jangan ubah setelan
PresetOtomatis. Eksplisit lewat nitro.preset: 'vercel'
Output directoryBiarkan kosong
Mode renderingrouteRules di nuxt.config.ts
Env variableruntimeConfig + prefiks NUXT_

Untuk SvelteKit langkahnya mirip tapi adapternya harus dipasang manual — lihat cara deploy SvelteKit ke Vercel. Kalau deploy-mu gagal, cek 15 error deploy paling umum.

Untuk memahami kapan tiap mode rendering dipakai, lihat SSG vs SSR vs CSR. Gambaran menyeluruh soal deploy ada di panduan lengkap deploy website.