This document collects frequently asked questions, sharp edges, and known issues in this site’s content architecture. It also doubles as a regression test for our more expressive markdown/MDX features: frontmatter validation, advanced code blocks, callouts, and more.
If you are reading this in the browser, the fact that it renders at all is already a good sign that the content layer, routing, and MDX runtime are configured correctly.
Frontmatter and content collections#
Why are some legacy posts failing validation?#
The current blog schema enforces a stricter frontmatter contract:
// apps/site/src/content/config.ts (excerpt)const blog = defineCollection({ type: 'content', schema: ({ image, extensions }) => z.object({ title: z.string(), date: z.coerce.date(), description: z.string().optional(), published: z.coerce.date().optional(), author: z.string().optional(), tags: z.array(z.string()).default([]), draft: z.boolean().default(false), heroImage: image().optional(), toc: z.boolean().default(true), updated: z.coerce.date().optional(), slug: z.string().optional(), ...extensions.seo(), }),});Common migration issues:
-
Old fields are no longer recognized
Legacy frontmatter like the following does not match the schema:
pubDate: 2022-03-01lastModDate: 2022-04-10ogImage: trueshare: truegiscus: truesearch: trueThese need to be converted:
date: 2022-03-01 # replaces pubDateupdated: 2022-04-10 # replaces lastModDate# ogImage / share / giscus / search are removed or handled via layout logic -
Missing required
datePosts with only a
titlewill fail. At minimum you need:title: My Postdate: 2025-01-01Everything else is optional, but strongly recommended.
Drafts, publication dates, and sorting#
How do drafts work?#
-
draft: trueprevents a post from appearing in public listing pages. -
You can still preview drafts locally or on authenticated deployments.
-
Listings should filter with something like:
const posts = (await getCollection('blog')).filter((entry) => !entry.data.draft).sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
Which date is used for sorting?#
By default, listings sort by date. The published field is available for cases where:
- You want to distinguish the content creation date (
date) from the first public publication date (published). - You have migrated posts from another system and want to preserve their original publication dates.
A typical pattern:
const effectiveDate = entry.data.published ?? entry.data.date;Tags and taxonomy pages#
Why are some tag or category pages empty?#
Tag pages are only populated if posts provide tags in frontmatter:
tags: - astro - content-collections - metaIf a tag page exists (e.g. /tags/astro) but appears empty:
- Confirm that at least one post includes
astroin itstagsarray. - Ensure the tag slugification logic in your tags route matches the way you render tag links in posts.
Known limitations#
Markdown vs MDX#
The content pipeline supports both .md and .mdx for blog posts. There are, however, some edge cases.
1. JSX in .md files#
Plain .md files do not support JSX:
<!-- This will not work in .md files --><MyComponent foo="bar" />If you need JSX:
- Rename the file to
.mdx, or - Replace the JSX with fenced code blocks or shortcodes/macros that are expanded at build time.
2. Imported components and server-only logic#
When using .mdx:
- Import components at the top of the document.
- Keep server-only logic out of MDX content; favor props passed from Astro pages/layouts instead.
import { FancyCallout } from '~/components/blog/FancyCallout';
<FancyCallout level="info"> MDX is great for interactive examples, but avoid heavy server-side logic here.</FancyCallout>Code blocks, syntax highlighting, and examples#
This site uses fenced code blocks with language hints for syntax highlighting.
```tsfunction hello(name: string): string { return `Hello, ${name}`;}Will render as:
```tsfunction hello(name: string): string { return `Hello, ${name}`;}For shell examples, prefer bash:
pnpm installpnpm run devTOC (table of contents) behavior#
toc: true(default) enables automatic table-of-contents generation where supported.toc: falsedisables it for the current article, while leaving global behavior unchanged.
This post sets toc: true in its frontmatter to validate that TOC rendering continues to work with the new schema.
Search and indexing#
If your search indexer relies on frontmatter, ensure that:
- It uses
title,description, andtagsfrom the schema. - It respects
draft: trueand excludes drafts from the public index. - It handles
updatedcorrectly, for example to boost recently-updated content.
A minimal indexable representation might look like:
type SearchDocument = { slug: string; title: string; description?: string; tags: string[]; date: string; updated?: string;};Troubleshooting checklist#
If a post fails to build or does not appear as expected:
-
Validate frontmatter against the schema:
- Required:
title,date. - Optional but recommended:
description,author,tags,published,updated,heroImage.
- Required:
-
Verify file extension:
- Use
.mdfor pure markdown. - Use
.mdxfor JSX or imported components.
- Use
-
Confirm routing:
- The collection is configured in
content.config.ts. - The slug is derived as expected (filename or explicit
slugfield).
- The collection is configured in
-
Check draft status:
- Ensure
draftisfalsefor content that should be public.
- Ensure
-
Inspect the layout:
- The appropriate layout is being used (blog vs TIL vs static pages).
- Article metadata props are passed correctly from the page to the layout.
If you have worked through this list and the issue persists, it is usually either:
- A schema mismatch (field names or types), or
- A routing mismatch (slug, collection, or path configuration).
Both are typically straightforward to diagnose once you look at the compiled output or the console error.
Summary#
This FAQ purposely uses:
- Rich frontmatter (title, dates, tags, hero image, draft flag)
- Multiple heading levels
- Code blocks in several languages
- TOC integration
to act as a live smoke test for the blog system. If anything here fails to render, it is a strong indication that the content pipeline or layout logic needs attention.