Skip to content

FAQs and Known Issues

Answers to common questions, limitations, and workarounds for this Astro content setup.

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:

  1. Old fields are no longer recognized

    Legacy frontmatter like the following does not match the schema:

    pubDate: 2022-03-01
    lastModDate: 2022-04-10
    ogImage: true
    share: true
    giscus: true
    search: true

    These need to be converted:

    date: 2022-03-01 # replaces pubDate
    updated: 2022-04-10 # replaces lastModDate
    # ogImage / share / giscus / search are removed or handled via layout logic
  2. Missing required date

    Posts with only a title will fail. At minimum you need:

    title: My Post
    date: 2025-01-01

    Everything else is optional, but strongly recommended.


Drafts, publication dates, and sorting#

How do drafts work?#

  • draft: true prevents 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
- meta

If a tag page exists (e.g. /tags/astro) but appears empty:

  1. Confirm that at least one post includes astro in its tags array.
  2. 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.

```ts
function hello(name: string): string {
return `Hello, ${name}`;
}
Will render as:
```ts
function hello(name: string): string {
return `Hello, ${name}`;
}

For shell examples, prefer bash:

Terminal window
pnpm install
pnpm run dev

TOC (table of contents) behavior#

  • toc: true (default) enables automatic table-of-contents generation where supported.
  • toc: false disables 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, and tags from the schema.
  • It respects draft: true and excludes drafts from the public index.
  • It handles updated correctly, 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:

  1. Validate frontmatter against the schema:

    • Required: title, date.
    • Optional but recommended: description, author, tags, published, updated, heroImage.
  2. Verify file extension:

    • Use .md for pure markdown.
    • Use .mdx for JSX or imported components.
  3. Confirm routing:

    • The collection is configured in content.config.ts.
    • The slug is derived as expected (filename or explicit slug field).
  4. Check draft status:

    • Ensure draft is false for content that should be public.
  5. 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.