Pelajari cara membangun proyek Next.js 14 terbaru dari nol, mengintegrasikan TypeScript, Tailwind CSS, dan deployment ke Vercel dalam langkah‑langkah praktis yang mudah diikuti.

1. Persiapan Lingkungan

Pastikan Anda memiliki Node.js versi 20.x atau lebih baru dan npm 10.x. Verifikasi dengan perintah:

node -v
npm -v

Jika belum terpasang, unduh installer resmi dari nodejs.org. Pastikan juga Git terinstal untuk mengelola repository.

2. Membuat Proyek Next.js 14

Gunakan create-next-app dengan flag --experimental-app untuk mengaktifkan App Router (default sejak v14).

npx create-next-app@latest my-next14-app \
  --ts \
  --eslint \
  --tailwind \
  --app-dir

Perintah di atas akan menghasilkan struktur folder berikut:

my-next14-app/
├─ app/            # App Router (page.tsx, layout.tsx)
├─ components/    # Komponen UI
├─ lib/            # Helper & utils
├─ public/        # Asset statis
├─ styles/        # Tailwind & globals.css
├─ next.config.mjs
├─ tsconfig.json
└─ package.json

Masuk ke direktori proyek:

cd my-next14-app

3. Instalasi Dependensi Tambahan

Untuk meningkatkan produktivitas, tambahkan beberapa paket populer:

# State management (optional) – Zustand
npm i zustand

# API fetching – TanStack Query
npm i @tanstack/react-query

# Form handling – React Hook Form & Zod
npm i react-hook-form zod @hookform/resolvers

# Linter & formatter – ESLint, Prettier (sudah ada, cukup update)
npm i -D eslint-config-prettier prettier

Setelah instalasi, jalankan npm run dev untuk memastikan server berjalan di http://localhost:3000.

4. Konfigurasi Tailwind CSS

File tailwind.config.js sudah dibuat otomatis. Tambahkan mode JIT dan path ke semua file UI:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

Pastikan globals.css mengimpor Tailwind directives:

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

5. Membuat Layout Global

Di folder app, buat file layout.tsx yang menjadi wrapper semua halaman:

import '@/styles/globals.css';
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Next.js 14 Demo',
  description: 'Demo app dengan App Router, TypeScript, dan Tailwind',
};

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

Catatan: gunakan className Tailwind untuk styling dasar.

6. Membuat Halaman Utama dengan Server Component

Buat file app/page.tsx:

import Link from 'next/link';
import { Button } from '@/components/ui/button';

export default function HomePage() {
  return (
    

Welcome to Next.js 14

Built with TypeScript, Tailwind, and the new App Router.

); }

Komponen Button adalah UI reusable yang akan kita buat selanjutnya.

7. Membuat UI Component Reusable

Di folder components/ui, buat button.tsx:

import React from 'react';
import clsx from 'clsx';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary';
}

export const Button: React.FC<ButtonProps> = ({
  variant = 'primary',
  className,
  children,
  ...props
}) => {
  const baseStyles = 'px-4 py-2 rounded-md font-medium transition-colors';
  const variants = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
  };
  return (
    
  );
};

Gunakan clsx untuk menggabungkan kelas secara dinamis (install npm i clsx jika belum).

8. Menambahkan API Route (Route Handler)

Di folder app/api/hello/route.ts, buat endpoint sederhana:

import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ message: 'Hello from Next.js 14 API!' });
}

Anda dapat menguji dengan curl http://localhost:3000/api/hello.

9. Integrasi TanStack Query untuk Data Fetching

Setup provider di app/layout.tsx (tambahkan di dalam body):

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

// ... dalam return:

  {children}

Contoh penggunaan di app/dashboard/page.tsx:

"use client";
import { useQuery } from '@tanstack/react-query';

export default function Dashboard() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['greeting'],
    queryFn: async () => {
      const res = await fetch('/api/hello');
      if (!res.ok) throw new Error('Network error');
      return res.json();
    },
  });

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    

Dashboard

{data?.message}

); }

Catatan: tambahkan "use client" di atas file karena hook React hanya dapat dipakai di client component.

10. Formulir dengan React Hook Form & Zod

Buat komponen components/contact-form.tsx:

"use client";
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

const schema = z.object({
  name: z.string().min(2, 'Name too short'),
  email: z.string().email('Invalid email'),
  message: z.string().min(10, 'Message too short'),
});

type FormData = z.infer<typeof schema>;

export function ContactForm() {
  const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  const onSubmit = async (data: FormData) => {
    // Simulasi API call
    await new Promise(r => setTimeout(r, 1000));
    alert(`Thank you, ${data.name}!`);
  };

  return (
    
{errors.name &&

{errors.name.message}

} {errors.email &&

{errors.email.message}

}