🔁 2026年リライト版 この記事は2020年4月に公開した「Netlify CMS + HugoでPage Bundles(コンテントと画像を同じ場所に配置)に対応する」を、2026年時点の Decap CMS(2023年の Netlify CMS フォーク / リネーム)前提で書き換えたものです。
2026年の状況 — Netlify CMS は Decap CMS にフォークされた
Netlify CMS は、2023年2月に元運営元 Netlify の開発撤退にともない、コミュニティで Decap CMS としてフォーク・改名されました。パッケージ名も netlify-cms から decap-cms へ移行しています。
- 旧:
https://unpkg.com/netlify-cms@^2.x/dist/netlify-cms.js - 新:
https://unpkg.com/decap-cms@^3.x/dist/decap-cms.js
バックエンド API やカスタマイズポイントはほぼ互換で、移行は基本的にスクリプトURLとバージョン指定の書き換えだけで済みます。本記事では Decap CMS 3.x + Hugo 0.140+ を前提に、Hugo Page Bundles 対応を解説します。
目指すディレクトリ構造
記事ごとに画像ファイルをまとめる Page Bundles の構成です。
.
├── archetypes
├── assets
├── config.yaml
├── content
│ └── posts
│ └── 2026
│ ├── 04
│ │ └── my-post/
│ │ ├── index.md
│ │ └── cover.png
│ └── 05
│ └── another-post/
│ ├── index.md
│ └── diagram.png
├── layouts
├── static
│ └── admin
│ ├── config.yml
│ └── index.html
└── themes
記事は leaf bundle(index.md をもつディレクトリ)として配置します。Decap CMS のコレクション設定で path を {{slug}}/index にするのがポイントです。
Decap CMS のスクリプト読み込み(2026年版)
static/admin/index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Content Manager</title>
</head>
<body>
<script src="https://unpkg.com/decap-cms@^3.8.0/dist/decap-cms.js"></script>
</body>
</html>
Decap CMS の config.yml(Page Bundles 対応)
static/admin/config.yml:
backend:
name: git-gateway
branch: main # 2020年当時は master だったが現在は main が標準
media_folder: static/images
public_folder: /images
publish_mode: editorial_workflow
collections:
- name: blog
label: Blog
folder: content/posts
create: true
slug: '{{fields.slug}}'
# ★ここが Page Bundle の肝
path: '{{year}}/{{month}}/{{slug}}/index'
# 記事内の画像を同じディレクトリに保存
media_folder: ''
public_folder: ''
preview_path: 'posts/{{year}}/{{month}}/{{slug}}/'
identifier_field: title
fields:
- { label: Title, name: title, widget: string }
- { label: Publish Date, name: date, widget: datetime, format: 'YYYY-MM-DD' }
- { label: Tags, name: tags, widget: list, required: false }
- { label: Draft, name: draft, widget: boolean, default: false }
- { label: Body, name: body, widget: markdown }
- { label: Slug, name: slug, widget: string }
各フィールドの役割:
path: '{{year}}/{{month}}/{{slug}}/index'
folder を起点に、上記パスのマークダウンファイル(.md は自動付与)が生成されます。末尾が /index になっているのがポイント。これで Hugo が leaf bundle として認識します。
content/posts/2026/04/my-post/index.md
media_folder: '' / public_folder: ''
どちらも空文字列にすると、記事 Markdown と同じディレクトリに画像ファイルが配置される ようになります。
結果、画像は:
content/posts/2026/04/my-post/cover.png
Markdown には:

という 相対パス で埋め込まれ、Hugo がレンダリング時に各ページバンドル内の資産として適切に解決してくれます。
Hugo 側の対応(2026年)
Hugo 0.140+ では、リソース画像の取り扱いに imageProcessing や resources.Get を使えます。layouts/_default/_markup/render-image.html で画像レンダリングをカスタマイズする例:
{{ $image := .Page.Resources.GetMatch .Destination }}
{{ if $image }}
{{ $small := $image.Resize "800x webp q80" }}
<img src="{{ $small.RelPermalink }}" alt="{{ .Text }}" loading="lazy">
{{ else }}
<img src="{{ .Destination }}" alt="{{ .Text }}">
{{ end }}
これで、Decap CMS から投稿された画像は WebP 化・リサイズされた上で配信されます。
ローカルテストも忘れずに
Decap CMS をローカルで動かす方法は ローカルホストでDecap CMS(旧Netlify CMS)をテストする を参照してください(記事タイトルは旧称のまま残しています)。