What this usually means
Astro's content layer scans the `src/content/` directory and matches it against the definitions in `src/content/config.ts`. A 'collection not found' error means there's a mismatch: either the folder name doesn't match the collection key in config (including case sensitivity), the `config.ts` file has a syntax error that prevents it from loading, or the collection directory is missing entirely. On case-sensitive file systems (Linux, macOS with case-sensitive volumes), even a capital letter difference causes this. Another common cause is that the collection's schema definition references a type that doesn't exist, causing the whole config to fail silently.
The first ten minutes — establish facts before touching code.
- 1Run `ls src/content/` to verify the collection folder exists and matches the name in your error message exactly (case-sensitive).
- 2Check `src/content/config.ts` — ensure the collection key (e.g., `posts`) matches the folder name exactly.
- 3Run `npx astro sync` and look for any JSON parse or schema errors in the output.
- 4Inspect `node_modules/.astro/collections/` for a `.json` file matching your collection name; if missing, config didn't load.
- 5Add a `console.log('config loaded')` inside the `collections` definition in config.ts to see if it executes during build.
- 6Check for hidden characters or BOM in config.ts using `cat -A src/content/config.ts` (unix) or a hex editor.
The specific files, logs, configs, and dashboards that usually own this bug.
- searchsrc/content/config.ts — the collection definitions and schemas
- searchsrc/content/<collection-name>/ — the actual content folder
- searchnode_modules/.astro/collections/ — generated collection metadata (check if file exists)
- searchastro.config.mjs — any `content` configuration (e.g., custom `src` path)
- searchBuild logs (CI or terminal) — look for `Collection "<name>" not found` line number
- search.astro/types.d.ts — generated TypeScript types; if collection missing here, config hasn't loaded
Practical causes, not theory. These are the things you will actually find.
- warningFolder name vs config key case mismatch (e.g., `Blog` folder but `blog` in config on Linux)
- warningCollection directory deleted or renamed without updating config
- warningSyntax error in `config.ts` (missing import, wrong type, trailing comma in schema)
- warningCustom `src` directory in `astro.config.mjs` not pointing to the right path
- warningSchema definition uses `z.object()` but the actual content file has missing fields, causing collection to fail validation and be ignored
- warning`astro sync` not run after adding a new collection (stale generated types)
Concrete fix directions. Pick the one that matches your root cause.
- buildNormalize folder name and config key to lowercase, or enforce case on your OS.
- buildIf using a custom `src` path, ensure `src/content` exists under that custom directory.
- buildFix any TypeScript errors in config.ts; use `defineCollection` and `z` properly; run `astro check`.
- buildRun `npx astro sync` to regenerate collection metadata after changes.
- buildIf collection is optional, use `z.optional()` or `z.default()` to avoid schema mismatch skipping the entire collection.
- buildRestart the Astro dev server completely after config changes — hot reload sometimes misses collection updates.
A fix you cannot prove is a guess. Close the loop.
- verifiedRun `npx astro build` without the error — build succeeds.
- verifiedCall `getCollection('<name>')` in a component and render the items; the page loads correctly.
- verifiedCheck `node_modules/.astro/collections/<name>.json` exists and contains correct entries.
- verifiedRun `astro check` and see zero errors related to collections.
- verifiedNavigate to the page that uses the collection in dev mode; confirm data renders.
- verifiedFor CI, add a step to run `astro check` before build to catch collection issues early.
Things that make this bug worse or harder to find.
- warningDon't rename folders without updating config.ts — they must match exactly.
- warningDon't ignore `astro check` warnings about collection schemas; they often precede build failures.
- warningDon't assume case-insensitivity — always use lowercase folder names to be safe across all OS.
- warningDon't delete `node_modules/.astro/` manually; run `astro sync` if you suspect stale data.
- warningDon't leave unused collection folders in `src/content/` — they'll be scanned and may cause confusion.
- warningDon't forget to commit `src/content/config.ts` changes; the collection definition is source of truth.
The Case of the Missing Blog Collection in CI
Timeline
- 09:15Push to main branch; GitHub Actions build starts.
- 09:16Build fails with error: `Collection "blog" not found`.
- 09:17Check `src/content/` — folder `Blog/` exists (capital B).
- 09:18Check `src/content/config.ts` — collection key is `blog` (lowercase b).
- 09:20Local dev on macOS works fine because of case-insensitive filesystem.
- 09:22Rename folder: `mv src/content/Blog src/content/blog`.
- 09:23Commit and push; build passes.
- 09:30Add `astro check` to CI pipeline to catch future case mismatches.
I pushed a new feature that added a blog collection to our Astro site. The build failed instantly in CI with `Collection "blog" not found`. I was confused because it worked perfectly on my Mac. I checked the CI logs — same error, no additional context.
I listed the contents of `src/content/` and saw `Blog/` with a capital B. Our config had `blog` lowercase. On macOS, the filesystem is case-insensitive by default, so `getCollection('blog')` found the `Blog` folder. But the Linux CI server is case-sensitive, so it didn't match. The fix was a simple rename.
I realized we had no case validation in our CI pipeline. I added `astro check` to the build script and enforced that all collection folders must be lowercase in our team's coding standards. Now any case mismatch is caught before merge.
Root cause
Case mismatch between folder name (`Blog`) and config key (`blog`) on a case-sensitive filesystem.
The fix
Renamed `src/content/Blog` to `src/content/blog` to match the config key.
The lesson
Always use lowercase for collection folder names to avoid cross-platform case-sensitivity issues. Add `astro check` to CI to catch these early.
Astro scans `src/content/` at build time and looks for a `config.ts` (or `.js`, `.mjs`) in that directory. The `config.ts` exports a `collections` object where keys are collection names and values are collection definitions. Each definition includes a schema and optionally a loader.
When you call `getCollection('posts')`, Astro looks for a folder named `posts` under `src/content/` and reads all Markdown/MDX files inside. It validates each file against the schema. If the folder doesn't exist or the config fails to load, you get 'Collection not found'.
A single syntax error in `config.ts` can prevent the entire collections object from being parsed. For example, a missing comma in a `z.object()` definition or using an undefined reference (like `z.string().min(1)` without importing `z`).
If the schema has a required field that the content file lacks, Astro may skip that file entirely, making the collection appear empty. Use `z.optional()` or `z.default()` for fields that aren't guaranteed in every file.
Always run `astro check` after editing `config.ts` — it catches TypeScript errors that would otherwise surface as silent collection failures.
Astro generates type definitions in `.astro/types.d.ts` based on your collections. If you add a new collection but don't run `astro sync`, the types won't exist and `getCollection` calls may fail at runtime (though the build may still work if you don't use TypeScript).
If you see TypeScript errors about unknown collection names, run `npx astro sync` to regenerate. This file is also cached in `node_modules/.astro/collections/`. Deleting `node_modules` and reinstalling can clear stale cache.
In CI, ensure `astro sync` is run before build, especially if you have a `postinstall` script that does this.
If you set a custom `src` directory in `astro.config.mjs` (e.g., `srcDir: './app'`), Astro expects content collections under `app/content/`. If you forget to move the folder or the path is wrong, collections won't be found.
Check the `srcDir` value in your config and verify that `src/content` exists relative to that path. Use an absolute path to avoid ambiguity.
Remember that `astro.config.mjs` changes may not be picked up by hot reload — restart the dev server entirely.
Frequently asked questions
Why does `getCollection('blog')` return an empty array even though the folder has files?
Likely a schema validation failure. Check that each file's frontmatter matches the schema defined in `config.ts`. Use `astro check` to see per-file errors. Also ensure the collection key in config matches the folder name exactly (case-sensitive).
I get 'Collection not found' only in production build, not in dev. What's happening?
This is almost always a case-sensitivity issue. Your dev environment (macOS/Windows) is case-insensitive, but your production server (Linux) is case-sensitive. Rename folders to lowercase and keep config keys lowercase. Also check if your CI pipeline has a different filesystem.
Can I have nested folders inside a collection?
Astro does not support nested folders within a single collection. All content files must be directly inside the collection folder. If you need subdirectories, create separate collections (e.g., `blog-2024`, `blog-2025`) or use tags/filters in your schema.
What does `astro sync` do exactly?
`astro sync` regenerates the TypeScript type definitions for your content collections (`src/content/types.generated.d.ts` or `.astro/types.d.ts`) and updates the collection cache in `node_modules/.astro/collections/`. Run it after adding or modifying a collection or its schema.
My collection folder exists, config looks correct, but still 'not found'. What else can I try?
Check for hidden files (like `.DS_Store`) that might interfere. Ensure `config.ts` is in `src/content/` not `src/`. Try deleting `node_modules/.astro` and running `astro sync` again. Also verify that there's no syntax error in `config.ts` by running `node -e "require('./src/content/config.ts')"` (adjust path).