Menu
📱 Lihat versi lengkap (non-AMP)
Hugo Headless CMS Content Management

Hugo dengan Headless CMS: Integrasi Strapi, Contentful, dan Sanity

Editor: Hendra WIjaya
Update: 3 February 2026
Baca: 5 menit

Hugo dengan Headless CMS: Integrasi Strapi, Contentful, dan Sanity

Headless CMS adalah pendekatan modern dalam content management yang memisahkan backend content repository dari frontend presentation layer. Hugo sebagai static site generator dapat diintegrasikan dengan berbagai headless CMS untuk memberikan pengalaman editing yang powerful kepada content creators. Panduan ini akan membahas cara mengintegrasikan Hugo dengan tiga headless CMS populer: Strapi, Contentful, dan Sanity.

Integrasi headless CMS dengan Hugo memberikan yang terbaik dari dua dunia: performa dan keamanan static site dari Hugo, dengan flexible dan user-friendly content management dari headless CMS. Pendekatan ini sangat cocok untuk tim yang menginginkan content management capabilities tanpa mengorbankan static site benefits.

Keunggulan Headless CMS dengan Hugo

Integrasi headless CMS dengan Hugo menawarkan banyak keunggulan yang menjadikannya pilihan populer untuk proyek modern. Content creators dapat menggunakan interface yang familiar untuk mengelola konten tanpa perlu memahami Git atau Markdown. API-driven content memungkinkan konten dari berbagai sources untuk di-aggregate dan di-present secara konsisten. Multi-channel publishing memungkinkan konten yang sama di-deploy ke website, mobile apps, dan platform lain. Scalability yang excellent karena headless CMS dapat handle konten dalam jumlah besar dengan baik.

Integrasi dengan Strapi

Strapi adalah open-source headless CMS yang dibangun dengan Node.js. Strapi menawarkan flexibility dan customization yang tinggi.

Setup Strapi

# Install Strapi
npx create-strapi-app@latest my-strapi --quickstart

Content Types di Strapi

Buat content types sesuai kebutuhan:

Article Collection Type:

  • title (Text)
  • slug (UID)
  • content (Rich Text)
  • excerpt (Text)
  • featuredImage (Media)
  • category (Relation to Category)
  • publishedAt (Datetime)

Category Collection Type:

  • name (Text)
  • slug (UID)
  • description (Text)

Fetch Content dari Strapi di Hugo

Buat script untuk fetch dan generate konten:

// scripts/fetch-strapi.js
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');

const STRAPI_URL = process.env.STRAPI_URL || 'http://localhost:1337';
const API_TOKEN = process.env.STRAPI_API_TOKEN;

async function fetchContent() {
    // Fetch articles
    const articlesRes = await fetch(`${STRAPI_URL}/api/articles?populate=*`, {
        headers: {
            'Authorization': `Bearer ${API_TOKEN}`
        }
    });
    const articles = await articlesRes.json();
    
    // Generate markdown files
    articles.data.forEach(article => {
        const frontmatter = {
            title: article.attributes.title,
            slug: article.attributes.slug,
            date: article.attributes.publishedAt,
            description: article.attributes.excerpt,
            image: article.attributes.featuredImage?.data?.attributes?.url,
            categories: [article.attributes.category?.data?.attributes?.name]
        };
        
        const markdown = `---\n${yaml.stringify(frontmatter)}---\n\n${article.attributes.content}`;
        
        const filePath = path.join(__dirname, '../content/articles', `${article.attributes.slug}.md`);
        fs.writeFileSync(filePath, markdown);
    });
    
    console.log(`Generated ${articles.data.length} articles`);
}

fetchContent().catch(console.error);

Hubungkan dengan Build Pipeline

// package.json
{
  "scripts": {
    "prebuild": "node scripts/fetch-strapi.js",
    "build": "hugo",
    "dev": "node scripts/fetch-strapi.js && hugo server"
  }
}

Integrasi dengan Contentful

Contentful adalah cloud-based headless CMS yang menawarkan reliability dan features enterprise-grade.

Setup Contentful

  1. Buat account di contentful.com
  2. Create space baru
  3. Buat content types
  4. Generate API credentials

Content Model di Contentful

Blog Post Content Type:

  • title (Short text)
  • slug (Short text, generate from title)
  • body (Long text atau Rich text)
  • featuredImage (Media)
  • publishDate (Date & time)
  • author (Reference ke Author content type)

Fetch Content dari Contentful

// scripts/fetch-contentful.js
const fs = require('fs');
const path = require('path');
const contentful = require('contentful');

const client = contentful.createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});

async function fetchPosts() {
    const entries = await client.getEntries({
        content_type: 'blogPost',
        order: '-fields.publishDate'
    });
    
    entries.items.forEach(entry => {
        const frontmatter = {
            title: entry.fields.title,
            slug: entry.fields.slug,
            date: entry.fields.publishDate,
            description: entry.fields.excerpt,
            image: entry.fields.featuredImage?.fields?.file?.url,
            author: entry.fields.author?.fields?.name
        };
        
        const markdown = `---\n${yaml.stringify(frontmatter)}---\n\n${entry.fields.body}`;
        
        const filePath = path.join(__dirname, '../content/posts', `${entry.fields.slug}.md`);
        fs.writeFileSync(filePath, markdown);
    });
    
    console.log(`Generated ${entries.items.length} posts`);
}

fetchPosts().catch(console.error);

Setup Environment Variables

# .env
CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_access_token

Integrasi dengan Sanity

Sanity adalah headless CMS dengan real-time collaboration dan structured content capabilities.

Setup Sanity

# Install Sanity CLI
npm install -g @sanity/cli

# Initialize project
sanity init

Schema di Sanity

// sanity/schemas/post.js
export default {
  name: 'post',
  title: 'Post',
  type: 'document',
  fields: [
    {
      name: 'title',
      title: 'Title',
      type: 'string',
    },
    {
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {
        source: 'title',
      },
    },
    {
      name: 'body',
      title: 'Body',
      type: 'array',
      of: [{type: 'block'}],
    },
    {
      name: 'featuredImage',
      title: 'Featured Image',
      type: 'image',
      options: {
        hotspot: true,
      },
    },
    {
      name: 'categories',
      title: 'Categories',
      type: 'array',
      of: [{type: 'reference', to: {type: 'category'}}],
    },
  ],
}

Fetch Content dari Sanity

// scripts/fetch-sanity.js
const fs = require('fs');
const path = require('path');
const { createClient } = require('@sanity/client');

const client = createClient({
  projectId: process.env.SANITY_PROJECT_ID,
  dataset: 'production',
  useCdn: true,
  apiVersion: '2024-01-01',
});

async function fetchPosts() {
    const query = `*[_type == "post"] | order(_createdAt desc) {
        _id,
        title,
        "slug": slug.current,
        _createdAt,
        body,
        "imageUrl": featuredImage.asset->url
    }`;
    
    const posts = await client.fetch(query);
    
    posts.forEach(post => {
        const frontmatter = {
            title: post.title,
            slug: post.slug,
            date: post._createdAt,
            description: 'Post description',
            image: post.imageUrl
        };
        
        // Convert Portable Text ke Markdown
        const body = convertPortableTextToMarkdown(post.body);
        
        const markdown = `---\n${yaml.stringify(frontmatter)}---\n\n${body}`;
        const filePath = path.join(__dirname, '../content/posts', `${post.slug}.md`);
        fs.writeFileSync(filePath, markdown);
    });
    
    console.log(`Generated ${posts.length} posts`);
}

fetchPosts().catch(console.error);

Automate dengan Webhooks

Setup Webhook di CMS

Contentful Webhook:

  • URL: https://your-cicd.com/webhook/contentful
  • Trigger: Publish, Unpublish

Strapi Webhook:

  • URL: https://your-cicd.com/webhook/strapi
  • Events: After Publish, After Update

Sanity Webhook:

  • URL: https://your-cicd.com/webhook/sanity
  • Trigger: On Create, On Update, On Delete

CI/CD Webhook Handler

// functions/webhook.js
const execSync = require('child_process').execSync;

exports.handler = async (event) => {
    // Verify webhook signature
    // const signature = event.headers['x-webhook-signature'];
    
    // Trigger rebuild
    try {
        execSync('git pull origin main', { cwd: '/path/to/repo' });
        execSync('npm run build', { cwd: '/path/to/repo' });
        return { statusCode: 200, body: 'Build triggered' };
    } catch (error) {
        return { statusCode: 500, body: error.message };
    }
};

Perbandingan Headless CMS

FiturStrapiContentfulSanity
PricingFree (self-hosted)Free tier + paidFree tier + paid
Self-hostedYaTidakTidak
Real-time collabTidakYaYa
APIGraphQL/RESTGraphQL/RESTGROQ
Image CDNCustomBuilt-inBuilt-in
Portable TextPluginRich TextNative
WebhooksYaYaYa

Best Practices

Caching Strategy

Implementasikan caching untuk mengurangi API calls:

// scripts/cache-content.js
const cache = new Map();
const CACHE_TTL = 3600000; // 1 hour

async function getContent(key, fetcher) {
    const cached = cache.get(key);
    if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
        return cached.data;
    }
    
    const data = await fetcher();
    cache.set(key, { data, timestamp: Date.now() });
    return data;
}

Content Sync

Implementasikan incremental sync untuk performance:

// scripts/incremental-sync.js
async function syncContent() {
    // Get last sync timestamp
    const lastSync = getLastSyncTimestamp() || 0;
    
    // Fetch only updated content
    const updates = await fetchUpdatesSince(lastSync);
    
    // Process updates
    for (const item of updates) {
        await updateContentFile(item);
    }
    
    // Update sync timestamp
    updateLastSyncTimestamp(Date.now());
}

Image Handling

Lakukan download dan optimize images lokal:

// scripts/download-images.js
const download = require('download');
const sharp = require('sharp');

async function processImages() {
    const posts = getAllPosts();
    
    for (const post of posts) {
        if (post.image) {
            const imageBuffer = await download(post.image);
            await sharp(imageBuffer)
                .resize(800, null, { withoutEnlargement: true })
                .webp({ quality: 80 })
                .toFile(`static/img/${post.slug}.webp`);
        }
    }
}

Kesimpulan

Integrasi Hugo dengan headless CMS memberikan fleksibilitas dalam content management sambil mempertahankan static site benefits. Pilih headless CMS berdasarkan kebutuhan tim, budget, dan technical requirements. Strapi untuk kontrol penuh dengan self-hosted, Contentful untuk enterprise-grade reliability, atau Sanity untuk real-time collaboration.

Artikel Terkait

Bagikan:

Link Postingan: https://www.tirinfo.com/hugo-headless-cms/