Next.js 14 telah menjadi standar de‑facto untuk building React apps dengan server‑side rendering, streaming, dan dukungan penuh TypeScript. Tutorial ini akan membimbing Anda langkah demi langkah mulai dari instalasi, konfigurasi App Router, integrasi Tailwind CSS, hingga deployment otomatis ke Vercel dengan best practice terbaru di 2026.

1. Persiapan Lingkungan

Sebelum memulai pastikan Anda memiliki:

  • Node.js 20.15+ (download di nodejs.org)
  • npm 10.7+ atau Yarn 4 (pnpm juga didukung)
  • Akun Vercel (free tier cukup untuk testing)
  • Git terinstall untuk version control

Verifikasi instalasi:

node -v
npm -v
git --version

2. Membuat Proyek Next.js 14 Baru

Gunakan create-next-app dengan flag --app untuk mengaktifkan App Router (fitur default sejak v13, tapi tetap penting di v14).

npx create-next-app@latest my-next14-app --typescript --app
cd my-next14-app

Struktur folder utama akan tampak seperti:

app/
  layout.tsx
  page.tsx
  (protected)/
    page.tsx
public/
styles/
next.config.mjs
package.json

3. Mengintegrasikan Tailwind CSS 3.4

Tailwind tetap menjadi pilihan utama untuk utility‑first styling. Ikuti langkah berikut:

  1. Instal dependensi:
npm i -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init -p

File tailwind.config.cjs akan dibuat. Modifikasi menjadi:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}",
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}"
  ],
  theme: {
    extend: {
      colors: {
        primary: "#0ea5e9",
        secondary: "#64748b"
      }
    }
  },
  plugins: []
};

Selanjutnya, pada ./styles/globals.css tambahkan directive Tailwind:

@tailwind base;
@tailwind components;
@tailwind utilities;

Import file CSS di app/layout.tsx:

import "./styles/globals.css";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    
      
        {children}
      
    
  );
}

4. Menyiapkan TypeScript Strict Mode & ESLint

Next.js 14 mengaktifkan strict secara default, tapi pastikan tsconfig.json memiliki:

{
  "extends": "next/core-web-vitals",
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Instal ESLint dengan konfigurasi Next.js:

npm i -D eslint@latest eslint-config-next@latest
npx eslint --init

Pilih Use a popular style guideNext.js. Tambahkan rule tambahan untuk React Hooks:

{
  "extends": ["next", "next/core-web-vitals"],
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

5. Membuat Routing & Protected Pages dengan App Router

App Router menggunakan folder app dan file layout.tsx untuk layout global.

5.1. Membuat Layout Publik

// app/layout.tsx (already created)

5.2. Membuat Halaman Home

// app/page.tsx
export default function HomePage() {
  return (
    

Selamat Datang di Next.js 14

Aplikasi modern dengan App Router & Tailwind CSS.

); }

5.3. Membuat Route Terproteksi

Gunakan middleware untuk autentikasi JWT atau NextAuth v5 (rilis 2026). Contoh sederhana dengan next-auth:

// app/(protected)/layout.tsx
import { getServerSession } from "next-auth";
import { authOptions } from "../auth";

export default async function ProtectedLayout({ children }: { children: React.ReactNode }) {
  const session = await getServerSession(authOptions);
  if (!session) {
    // Redirect ke login page
    return (

Redirecting...

); } return <>{children}; }

File app/auth.ts berisi konfigurasi NextAuth v5 yang mendukung OAuth 2.0, credential, dan Magic Link.

6. Menambahkan API Route dengan Server Actions (Next.js 14)

Server Actions memungkinkan Anda menulis fungsi async di komponen yang dieksekusi di server tanpa membuat endpoint terpisah.

// app/actions.ts
"use server";
export async function submitContact(formData: FormData) {
  // Simulasi penyimpanan ke DB
  await new Promise(r => setTimeout(r, 500));
  return { success: true };
}

Gunakan di komponen:

// app/contact/page.tsx
import { submitContact } from "../actions";

export default function ContactPage() {
  return (