Membangun Headless CMS dengan Strapi dan Next.js: API-First Content Management untuk Aplikasi Modern

Lhuqita Fazry
Web Development Headless CMS Strapi Next.js REST API
Membangun Headless CMS dengan Strapi dan Next.js: API-First Content Management untuk Aplikasi Modern

Mengapa Arsitektur CMS Monolitik Membatasi Aplikasi Frontend Modern

CMS monolitik seperti WordPress mengikat content storage, theming, dan rendering ke dalam satu server. Ketika halaman dirender, aplikasi harus mengeksekusi PHP, menarik data dari database, dan menghasilkan HTML di mesin yang sama dengan admin panel. Konsekuensinya, setiap perubahan tema menyentuh data konten, dan setiap permintaan halaman membebani satu infrastruktur yang sama.

Arsitektur headless memecah keterikatan ini dengan memisahkan content backend dari presentation layer. Konten disimpan dan dikelola di satu tempat, lalu disajikan melalui API — baik REST maupun GraphQL — sehingga frontend apa pun dapat mengonsumsinya. Next.js, aplikasi mobile, hingga static site dapat mengambil data yang sama dari satu sumber. Team content tidak lagi membutuhkan developer untuk menerbitkan artikel, dan developer tidak perlu menyentuh admin panel untuk mengubah tampilan.

Di sinilah Strapi berperan. Strapi adalah open-source headless CMS yang self-hosted, menyediakan admin panel siap pakai, dan otomatis menghasilkan REST API untuk setiap content-type yang kita definisikan. Trade-off ini layak diambil ketika kita menerbitkan konten ke banyak channel, memisahkan tim konten dan tim engineering, serta menginginkan isolasi performa antara admin dan frontend.

Membuat Proyek Strapi dan Mendefinisikan Content Model

Langkah pertama adalah menscaffold proyek Strapi menggunakan CLI. Pastikan Node.js versi 18 atau lebih baru sudah terpasang, lalu jalankan perintah berikut.

bashbash
npx create-strapi-app@latest my-cms --quickstart

Output:

text
✔ Creating a new Strapi application at /path/to/my-cms
✔ Installing dependencies...
✔ Strapi application was created successfully

Admin panel: http://localhost:1337/admin
Server:      http://localhost:1337

Perintah ini membuat proyek lengkap dengan struktur src/api/ untuk logic per content-type, src/admin/ untuk kustomisasi panel, serta konfigurasi database default. Ketika server berjalan, admin panel tersedia di http://localhost:1337/admin. Di sana kita membuat akun admin pertama dan mulai merancang content model melalui Content-Type Builder.

Gambar: Tampilan Content-Type Builder Strapi untuk mendefinisikan schema content type dan field relasi — Sumber: [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Screenshot_of_the_Open_Source_CMS_Strapi.png)

Strapi membedakan dua jenis content-type: collection type untuk konten berulang seperti Article dan Category, serta single type untuk konten sekali tayang seperti Homepage. Setiap tipe bisa diberi field beragam — teks, rich text, number, media, hingga relation. Relasi one-to-many (satu Category memiliki banyak Article) dan many-to-many (sebuah Article memiliki banyak tag) dibuat langsung melalui antarmuka visual tanpa menulis kode.

Gambar: Contoh relasi one-to-one, one-to-many, dan many-to-many dalam pemodelan data — Sumber: [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Entity_Relationship_Diagram_Examples.png)

Setelah content-type dibuat, periksa bagian Roles & Permissions di panel. Strapi membedakan peran Public dan Authenticated, masing-masing dengan hak akses per endpoint. Untuk kebutuhan awal, kita aktifkan akses baca pada endpoint artikel agar frontend bisa mengambil data.

Mengekspos Konten Melalui Strapi API dengan Authentication Token

Fullstack Web Development With Next.js
Web App • Beginner

Fullstack Web Development With Next.js

A practical, beginner-friendly, and project-based introduction to full-stack web...

Daftar

Strapi secara otomatis menghasilkan REST endpoint untuk setiap content-type. Content-type Article langsung dapat diakses melalui /api/articles, Category melalui /api/categories, dan seterusnya. Setiap endpoint mendukung operasi GET, POST, PUT, dan DELETE sesuai dengan hak akses yang diberikan.

Untuk mengamankan endpoint, generate API token dari menu Settings → API Tokens di admin panel. Token ini dikirim melalui header Authorization: Bearer pada setiap request. Dengan token tersebut, kita juga bisa memanfaatkan query parameters untuk memfilter, mengurutkan, dan menarik relasi sekaligus.

bashbash
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
  "http://localhost:1337/api/articles?populate=category&sort=publishedAt:desc"

Output:

jsonjson
{
  "data": [
    {
      "id": 1,
      "title": "Pengantar Headless CMS",
      "slug": "pengantar-headless-cms",
      "category": { "id": 2, "name": "Web Development" }
    }
  ],
  "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1 } }
}

Parameter populate=category meminta Strapi meng-include data relasi dalam satu respons, sehingga frontend tidak perlu melakukan request tambahan untuk mengambil nama kategori. Parameter sort mengatur urutan berdasarkan field publishedAt. Ini adalah pola yang sama dengan yang digunakan aplikasi web production — satu request, data lengkap.

Mengambil dan Merender Konten Strapi di Aplikasi Next.js App Router

Setelah API berjalan, kita siapkan frontend Next.js. Buat proyek dengan npx create-next-app@latest, lalu simpan URL dan token sebagai environment variables di file .env.local.

bashbash
STRAPI_API_URL=http://localhost:1337
STRAPI_API_TOKEN=YOUR_API_TOKEN

Selanjutnya kita buat modul data-fetching yang membungkus endpoint Strapi dengan tipe TypeScript, dan halaman artikel menggunakan server component App Router.

typescripttypescript
// src/lib/strapi.ts
export interface Article {
  id: number;
  title: string;
  slug: string;
  content: string;
}

export async function getArticles(): Promise<Article[]> {
  const res = await fetch(`${process.env.STRAPI_API_URL}/api/articles`, {
    headers: { Authorization: `Bearer ${process.env.STRAPI_API_TOKEN}` },
    next: { revalidate: 60 },
  });
  if (!res.ok) throw new Error(`Strapi request failed: ${res.status}`);
  const json = await res.json();
  return json.data;
}
typescripttypescript
// src/app/articles/[slug]/page.tsx
import { getArticles } from '@/lib/strapi';

export async function generateStaticParams() {
  const articles = await getArticles();
  return articles.map((article) => ({ slug: article.slug }));
}

export default async function ArticlePage({ params }: { params: { slug: string } }) {
  const articles = await getArticles();
  const article = articles.find((item) => item.slug === params.slug);

  if (!article) return <p>Artikel tidak ditemukan.</p>;

  return (
    <article>
      <h1>{article.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: article.content }} />
    </article>
  );
}

Alur kerjanya: Next.js memanggil server component saat build, server component melakukan fetch ke Strapi API, Strapi mengambil data dari database, dan hasilnya dirender menjadi HTML. generateStaticParams memberi tahu Next.js halaman mana saja yang harus di-generate secara statis berdasarkan daftar slug. Dengan next: { revalidate: 60 }, halaman di-revalidate setiap 60 detik sehingga konten baru tetap muncul tanpa full rebuild. Error states penting — jika Strapi tidak merespons, halaman menampilkan fallback alih-alih crash.

Untuk halaman detail, kita juga bisa mengekspor generateMetadata yang mengambil judul dan deskripsi dari data artikel lalu memetakannya ke tag <title> dan meta description. Metadata statis dihasilkan saat build, sementara metadata dinamis mengikuti konten yang ada di database. Pendekatan ini memastikan setiap halaman artikel memiliki judul dan deskripsi unik untuk SEO, tanpa menulis metadata secara manual per halaman.

Menangani Media Upload dan Alur Kerja Draft-and-Publish

Strapi menyediakan upload provider bawaan yang menyimpan gambar dan file di server, lalu menyajikannya melalui endpoint /uploads. Setiap media direkam dengan field formats yang berisi varian thumbnail, small, medium, dan large lengkap dengan dimensi piksel masing-masing.

Untuk menampilkan media di Next.js, gunakan komponen next/image dengan URL media Strapi sebagai sumber. Field width dan height dari formats kita manfaatkan untuk menghindari layout shift, sementara prop sizes dan priority mengoptimalkan pemuatan gambar sesuai konteks. Pendekatan ini menjaga performa karena Next.js melakukan resize dan lazy-loading secara otomatis.

Fitur draft-and-publish memungkinkan editor menyiapkan konten tanpa langsung mengeksposnya ke publik. Entri yang berstatus draft tersimpan di database tetapi tidak muncul di endpoint publik. Di sisi frontend, kita cukup memfilter dengan parameter publicationState=live pada query agar draft tidak bocor. Untuk kebutuhan preview, Strapi menyediakan mode draft yang bisa kita aktifkan sementara — editor melihat perubahan belum terbit di frontend tanpa mengubah status publikasi konten. Alur kerja ini menjaga kualitas konten: artikel ditulis, ditinjau dalam mode draft, lalu diterbitkan hanya ketika sudah final.

Memperkuat Setup Production dengan Caching, Monitoring, dan Keamanan

Sebelum meluncurkan ke production, ada beberapa langkah hardening yang perlu kita lakukan. Pertama, batasi CORS pada pengaturan server Strapi — ganti nilai default * dengan origin frontend production kita. Kebijakan ini mencegah domain lain mengirim request ke API.

Kedua, buat API token dengan scope minimal. Strapi mendukung pembuatan token per content-type, sehingga token frontend cukup diberi hak read pada endpoint yang benar-benar dibutuhkan. Ketiga, terapkan strategi caching di sisi Next.js dengan revalidate ISR seperti pada contoh sebelumnya — halaman statis tetap cepat sementara konten tetap segar.

Untuk observability, tambahkan logging pada lapisan data-fetching di Next.js dan catat durasi response dari Strapi. Peningkatan response time yang tiba-tiba sering kali menjadi indikator awal masalah database atau jaringan. Terakhir, deploy Strapi dan Next.js secara terpisah — masing-masing di lingkungannya sendiri sehingga keduanya bisa diskalakan secara independen ketika traffic meningkat. Dengan pemisahan ini, beban admin panel tidak pernah bersaing dengan beban rendering halaman publik.

Kita telah membahas bagaimana arsitektur headless memisahkan content dari presentation, cara mendefinisikan content model dan mengekspos REST API dengan Strapi, hingga mengambil serta merender konten tersebut di Next.js dengan caching dan keamanan yang tepat. Pola API-first content management ini kita praktikkan secara mendalam di track Web Development Bootcamp Rumah Coding, yang mencakup integrasi REST API, autentikasi, dan deployment production.

Kursus Terkait

TechConnect - Modern IT Job Portal
Kursus Premium Web App

Fullstack Web Development With Next.js

A practical, beginner-friendly, and project-based introduction to full-stack web development. Students will learn to build, secure, and deploy modern web applications from scratch using Next.js (App Router), React, Tailwind CSS, and a relational database. By the end of the course, students will have a fully functional, production-ready application to showcase in their portfolio.

Proyek Akhir

TechConnect - Modern IT Job Portal

  • Public Job Board: A responsive homepage displaying available job listings with dynamic routing for individual job detail pages.
  • Search & Filter: Basic functionality allowing users to find jobs based on keywords or categories.
  • User Authentication: Secure Sign Up, Log In, and Log Out workflows.
7 Weeks Beginner
Lihat Detail Kursus

Artikel Terkait