Skip to main content
Back to blog Copy Markdown
· 5 min read ·
astro debugging content collections typescript

Astro Debugging: Fixed "Missing Schema Fields" in 5 Min

Astro schema fields missing at runtime? You're probably editing src/content/config.ts instead of src/content.config.ts. Symptoms, cause, 4-step fix. →

Óscar Gallego

Óscar Gallego

Web Developer

A developer debugging Astro configuration files on a computer screen.
On this page

Why aren’t my Astro schema fields updating?

If you’ve added fields to your Astro Content Collections schema and they aren’t appearing, the most common cause is the configuration file’s location or name. As of Astro 6, the legacy src/content/config.ts path is gone; Astro reads only src/content.config.ts. (In Astro 5 the old path still worked, which is why this trap bites people mid-migration.)

Before you burn an afternoon on it (I did), run this checklist:

  1. Location. The config file lives at the root of src/, not inside src/content/. Correct: src/content.config.ts. Wrong: src/content/config.ts.
  2. Name. It must be called content.config.ts, exactly. Any other variation gets ignored.
  3. No duplicates. Search your project for a second configuration file Astro might be reading instead.
  4. Cache. Delete the .astro directory and restart the dev server to force Astro to regenerate types from the correct file.

Have you ever defined a field in your content collection schema, only for it to vanish at runtime? You’re not alone. I recently spent hours debugging schema fields that were inexplicably missing, despite being correctly defined.

TL;DR. My new schema fields were missing because I was editing src/content/config.ts. Astro only recognizes src/content.config.ts. I moved my changes to the correctly named and located file and deleted the duplicate.

What follows is the full debugging trail: the symptoms, the dead ends, and the fix.

The mystery of the disappearing schema fields

While adding a relatedSlug field to my blog’s schema for multilingual support, I hit a wall. The field was defined in the schema and present in the Markdown frontmatter, but completely absent from the post.data object.

The symptoms

My setup looked correct. The relatedSlug field was nowhere: not in the TypeScript types, not at runtime.

// src/content/config.ts
import { z, defineCollection } from "astro:content";

const blogCollection = defineCollection({
  schema: z.object({
    title: z.string(),
    // ... other fields
    relatedSlug: z.string().optional(), // WRONG: this field was missing!
  }),
});

export const collections = { blog: blogCollection };
  • Defined in the schema: relatedSlug was clearly part of the Zod object.
  • Present in the frontmatter: my .md files included relatedSlug: "some-slug".
  • Missing at runtime: 'relatedSlug' in post.data returned false.

Two out of three. The wrong two.

What didn’t work (everything I tried first)

I suspected a bug in Astro or Zod, so I threw workarounds at it. None of them moved the needle:

  1. Swapping .optional() for .default(""), hoping to force the field into existence. Still missing.
  2. Making it required. Astro should have thrown an error for the missing field. It didn’t. The field stayed absent.
  3. Renaming it. relatedSlug became translation to rule out a naming conflict. The new field vanished too.

That third result was the real clue. When even required fields are silently ignored, Astro isn’t reading your config at all.

The root cause: I was editing the wrong file

After hours of debugging, the answer was embarrassingly simple.

The Astro documentation gives the content collections config strict naming and location requirements.

  • Correct file: src/content.config.ts
  • My file: src/content/config.ts

I had accidentally created a configuration file inside the content directory. As of Astro 6, that legacy src/content/config.ts path is gone, so Astro ignored it completely and kept reading an older version of content.config.ts sitting at the src root.

One slash. Hours of my life.

The fix, in four steps

Once the root cause was identified, the fix was mechanical.

Step 1: confirm which file Astro is actually using

The generated types in .astro/ give you the answer.

// .astro/content.d.ts
// This line reveals the source of truth:
export type ContentConfig = typeof import("../src/content.config.js");

Step 2: consolidate and delete

I copied my latest schema definitions from the incorrect file (src/content/config.ts) into the correct one (src/content.config.ts), then deleted the duplicate.

# Delete the incorrect configuration file
rm src/content/config.ts

Step 3: make the correct file the only truth

With the duplicate gone, I made sure src/content.config.ts had the final schema.

// src/content.config.ts  CORRECT
import { z, defineCollection } from "astro:content";

const blogCollection = defineCollection({
  schema: z.object({
    // ... all my fields
    relatedSlug: z.string(), // CORRECT: now it works!
  }),
});

export const collections = { blog: blogCollection };

Step 4: clear the cache

To make sure Astro picked up the changes, clear the cache and restart the dev server.

# Clear the .astro cache directory
rm -rf .astro
# Restart the development server
npm run dev

After these steps, relatedSlug appeared in my types and at runtime. Like it had been there all along. Because it had.

The checklist to run before you blame the framework

Next time fields go missing, check these before anything clever:

  • Is your config file at src/content.config.ts?
  • Is it named content.config.ts exactly?
  • Is there only one content.config.ts in the whole project?
  • Have you tried deleting the .astro directory?
  • Does the file actually export const collections?

Master the conventions before you suspect the tool

Here’s the uncomfortable part. I spent those hours assuming the bug was in Astro or Zod, because blaming the tool feels better than checking a file path. The tool was fine. My directory tree wasn’t.

What felt like a deep framework bug was a misconfiguration with a five-minute fix. When a framework silently ignores you, the silence usually means it never heard you in the first place. Check its conventions before you open an issue.

Related reading: this exact rename, src/content/config.ts to src/content.config.ts, is one of the breaking changes covered in my Astro 5 to 6 migration guide, along with the rest of the traps that shipped with it.


P.S. What’s the dumbest file-location bug that ever ate your afternoon? Misery loves company. Tell me on Twitter/X.

Share this article

Related Posts