シリーズ目次 前章: 04. astro-paper.config.ts で設定する 次章: 06. AstroPaperで記事を整理する:ディレクトリ・URL・タグ
Table of contents
Open Table of contents
この章のねらい
AstroPaperで記事を書く作業は、src/content/posts/ にMarkdownファイルを足すだけです。ただしファイル先頭のフロントマターには書き方の決まりがあります。全項目と、公開・非公開を制御する仕組みを見ていきます。
最初の1本を書く
src/content/posts/hello-world.md を作り、次の内容を書きます。
---
title: "はじめての記事"
description: "AstroPaperで最初の記事を書いてみます。"
pubDatetime: 2026-08-02T09:00:00.000Z
tags:
- "日記"
---
ここから本文が始まります。
## 見出し
Markdownの記法がそのまま使えます。src/content/posts/hello-world.md
開発サーバーを起動していれば、これだけで /posts/hello-world/ に記事が表示されます。
フロントマターとは
ファイル先頭を --- で挟んだ部分がフロントマターです。ここに記事の属性(タイトル、日付、タグなど)をYAMLという形式で書きます。
YAMLは キー: 値 の形で書く設定用の記法です。階層は字下げで表し、配列は行頭の - で表します。
title: "記事タイトル"
tags:
- "タグ1"
- "タグ2"
書ける項目の一覧
| 項目 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
title | 文字列 | ○ | — | 記事タイトル。ページのH1見出しになる |
description | 文字列 | ○ | — | 記事の要約。一覧・SEO・OGPに使われる |
pubDatetime | 日時 | ○ | — | 公開日時 |
modDatetime | 日時 | — | なし | 更新日時 |
author | 文字列 | — | サイトの author | 著者名 |
featured | 真偽値 | — | false | トップページの「Featured」に載せる |
draft | 真偽値 | — | false | 下書きにする |
tags | 文字列の配列 | — | ["others"] | タグ |
ogImage | 画像またはURL | — | 自動生成 | SNS共有用の画像 |
canonicalURL | 文字列 | — | 自動生成 | 正規URL |
hideEditPost | 真偽値 | — | false | この記事だけ編集リンクを隠す |
timezone | 文字列 | — | サイトの timezone | この記事だけタイムゾーンを変える |
必須は title、description、pubDatetime の3つだけ。残りは省略したときに何が入るかさえ知っていれば、書く量はぐっと減ります。
検証の仕組み
フロントマターの形式は src/content.config.ts で定義されています。
const posts = defineCollection({
loader: glob({ pattern: "**/[^_]*.{md,mdx}", base: "./src/content/posts" }),
schema: ({ image }) =>
z.object({
author: z.string().default(config.site.author),
pubDatetime: z.date(),
modDatetime: z.date().optional().nullable(),
title: z.string(),
tags: z.array(z.string()).default(["others"]),
description: z.string(),
// ...
}),
});src/content.config.ts
ここで使われている z は Zod というライブラリです。この項目は文字列、この項目は日付、と形を宣言しておくと、条件を満たさない記事があったときにビルドが落ちて、どのファイルのどの項目が問題なのかを教えてくれます。
たとえば pubDatetime を書き忘れると、次のようなエラーが出ます。
[InvalidContentEntryDataError] posts → hello-world data does not match collection schema.
pubDatetime: Required
書式の誤りを公開前に必ず捕まえられる。これがREADMEにある type-safe markdown(型安全なMarkdown)の中身です。
検証は記事が公開される手前に置かれていて、通れば公開、通らなければビルドが止まります。
.default() の意味
author と tags には .default(...) が付いています。書かなかった場合に自動で入る値です。author を省略すればサイト設定の著者名が、tags を省略すれば ["others"] が入ります。
日時の書き方
pubDatetime はYAMLが日時として解釈できる形で書きます。ISO 8601形式が確実です。
pubDatetime: 2026-08-02T09:00:00.000Z
末尾の Z は協定世界時(UTC)を意味します。この値が、設定した timezone に変換されて画面に表示されます。
| 書いた値 | timezone: "Asia/Tokyo" での表示 |
|---|---|
2026-08-02T09:00:00.000Z | 2 Aug, 2026(日本時間 18:00) |
2026-08-02T20:00:00.000Z | 3 Aug, 2026(日本時間 翌 05:00) |
日本時間で書きたい場合は、オフセットを明示することもできます。
pubDatetime: 2026-08-02T18:00:00+09:00
日時を引用符で囲むと文字列として扱われ、日付型を期待するスキーマと合わずにエラーになります。日時には引用符を付けないと覚えてください。逆に
titleやdescriptionは、コロンなどがYAMLの区切り記号と衝突しないよう、常に引用符で囲むのが安全です。
書いた値と画面に出る値がずれるのは、この変換をはさんでいるためです。
modDatetime の効果
modDatetime を書くと、記事一覧の並び順が更新日時基準になり、日付表示も「Updated」に変わります。
new Date(b.data.modDatetime ?? b.data.pubDatetime).getTime()src/utils/getSortedPosts.ts
?? は、左が未設定なら右を使うという記法です。modDatetime があればそれを、なければ pubDatetime を使って並べ替えます。
記事を大きく書き直したときに modDatetime を足せば、一覧の先頭へ戻せます。
公開されるかどうかの判定
記事が一覧に出るかどうかは、次の順序で決まります。
判定の本体は src/utils/postFilter.ts です。
export function postFilter({ data }: CollectionEntry<"posts">) {
const isPublishTimePassed =
Date.now() >
new Date(data.pubDatetime).getTime() - config.posts.scheduledPostMargin;
return !data.draft && (import.meta.env.DEV || isPublishTimePassed);
}src/utils/postFilter.ts
読み解くと次のようになります。
draft: trueの記事は、いつでも除外される- 開発サーバー(
import.meta.env.DEVが真)では、下書き以外はすべて表示される - 本番ビルドでは、公開日時から猶予を引いた時刻を過ぎているものだけ表示される
下書き
draft: true
書きかけの記事はこれで隠せます。開発サーバーでも一覧に出なくなるので、確認したいときは一時的に false にしてください。
予約公開
未来の日時を pubDatetime に設定すると、その時刻まで公開されません。
pubDatetime: 2026-09-01T00:00:00.000Z
ただしAstroPaperは静的サイトなので、時刻が来ても勝手には公開されません。公開されるのは、その時刻を過ぎた後にビルドしたときです。予定どおりに出したいなら、ホスティングサービスの定期ビルド機能などを使ってください。
scheduledPostMargin(既定15分)は、この判定を少し前倒しにする猶予でした。00:00公開の記事を23:50のビルドに含めたい、といった場面で効きます。
_ で始まるファイルの扱い
src/content.config.ts の取り込みパターンは **/[^_]*.{md,mdx} です。[^_] は _ 以外の文字で始まるという条件なので、_draft.md のようなファイルは記事として認識されません。
ここで引っかかります。この条件が効くのはファイル名だけです。パターン先頭の **/ はディレクトリ名を問わないので、_notes/memo.md のように _ 付きディレクトリの中にある _ なしのファイルは、そのまま取り込まれます。しかもURLを組み立てる際に _ で始まるディレクトリは読み飛ばされるので、/posts/memo/ として公開されます。
除外したいMarkdownには、ディレクトリではなくファイル名の先頭に _ を付けてください。なお画像やSVGは .md / .mdx ではないため最初から対象外で、assets/ のようなディレクトリに分けるだけで十分です。
注目記事
featured: true
これを付けた記事は、トップページのFeatured欄に出ます。同時にRecent Postsからは外れるので、両方に重複して並ぶことはありません。
代表作や自己紹介の記事を固定表示したいときに使います。
トップページ上で置き場所が入れ替わる、と考えてください。
タグ
tags:
- "Astro"
- "初心者向け"
タグを付けると、/tags/ の一覧と /tags/<タグ名>/ の絞り込みページが自動で作られます。日本語のタグも使えます。タグとURLの関係は次章: 06. AstroPaperで記事を整理する:ディレクトリ・URL・タグで扱います。
記事ごとの上書き設定
サイト全体の設定を、特定の記事だけ変えたいときに使う項目です。
| 項目 | 用途 |
|---|---|
author | 寄稿記事など、著者が違う場合 |
timezone | 現地時間で書いた記事の日付を正しく見せたい場合 |
canonicalURL | 他サイトに掲載した記事の転載である場合 |
hideEditPost | 編集リンクを出したくない記事がある場合 |
ogImage | 自動生成ではなく専用の画像を使いたい場合 |
canonicalURL は入れておいてください。同じ内容が複数のURLに存在すると検索評価が分散するため、「本来の掲載場所はこちら」と宣言することで正しく集約されます。
テンプレート
新しい記事を書き始めるときのひな形として、次をコピーすると迷いません。
---
title: ""
description: ""
pubDatetime: 2026-08-02T09:00:00.000Z
featured: false
draft: true
tags:
- ""
---
## 見出し
本文
draft: true から始めて、完成したら false に変える。この運用にしておけば、書きかけを公開する事故は起きません。
要点
- フロントマターの必須項目は
title、description、pubDatetimeの3つで、それ以外は既定値が使われる。 src/content.config.tsのZodスキーマが形式を検証するため、書式の誤りはビルド時に必ず検出される。- 日時には引用符を付けず、
titleやdescriptionには引用符を付けるのが安全である。 - 公開判定は「下書きか → 開発中か → 公開時刻を過ぎたか」の順で行われ、静的サイトのため予約公開は次回ビルド時に反映される。
- 取り込み対象から外れるのは
_で始まるファイルだけで、ディレクトリ名に_を付けても中のMarkdownは公開される。
参考資料
- AstroPaper 記事追加ガイド — フロントマター各項目の公式説明
- テンプレート同梱ソース
src/content.config.ts— コレクション定義とZodスキーマ - テンプレート同梱ソース
src/utils/postFilter.ts— 下書きと予約公開の判定 - テンプレート同梱ソース
src/utils/getSortedPosts.ts— 並び順の決定 - Astro: Content Collections — コレクションとスキーマの仕組み
- Zod 公式ドキュメント — スキーマ定義の記法
シリーズ目次 前章: 04. astro-paper.config.ts で設定する 次章: 06. AstroPaperで記事を整理する:ディレクトリ・URL・タグ