{"record":{"id":"48dc63f799d60531","repo":"withastro/astro","slug":"legacycontentconfigerror","errorCode":"LegacyContentConfigError","errorMessage":"Found legacy content config file in \"${relativePath}\". Please move this file to \"src/content.config.${filename.split('.').at(-1)}\" and ensure each collection has a loader defined.","messagePattern":"Found legacy content config file in \"(.+?)\"\\. Please move this file to \"src/content\\.config\\.(.+?)\" and ensure each collection has a loader defined\\.","errorType":"error_code","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/content/utils.ts","lineNumber":737,"sourceCode":"};\n\nexport function getContentPaths(\n\t{ srcDir, root }: Pick<AstroConfig, 'root' | 'srcDir'>,\n\tfs: typeof fsMod = fsMod,\n\tlegacyCollectionsBackwardsCompat = false,\n): ContentPaths {\n\tconst pkgBase = new URL('../../', import.meta.url);\n\tconst configStats = searchConfig(fs, srcDir);\n\n\tif (!configStats.exists) {\n\t\tconst legacyConfigStats = searchLegacyConfig(fs, srcDir);\n\t\tif (legacyConfigStats.exists) {\n\t\t\tif (!legacyCollectionsBackwardsCompat) {\n\t\t\t\tconst relativePath = path.relative(\n\t\t\t\t\tfileURLToPath(root),\n\t\t\t\t\tfileURLToPath(legacyConfigStats.url),\n\t\t\t\t);\n\t\t\t\tthrow new AstroError({\n\t\t\t\t\t...AstroErrorData.LegacyContentConfigError,\n\t\t\t\t\tmessage: AstroErrorData.LegacyContentConfigError.message(relativePath),\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Use legacy config path when backwards compat is enabled\n\t\t\treturn getContentPathsWithConfig(root, srcDir, pkgBase, legacyConfigStats, fs);\n\t\t}\n\t}\n\n\tconst liveConfigStats = searchLiveConfig(fs, srcDir);\n\treturn {\n\t\troot: new URL('./', root),\n\t\tcontentDir: new URL('./content/', srcDir),\n\t\tassetsDir: new URL('./assets/', srcDir),\n\t\ttypesTemplate: new URL('templates/content/types.d.ts', pkgBase),\n\t\tvirtualModTemplate: new URL('templates/content/module.mjs', pkgBase),\n\t\tconfig: configStats,\n\t\tliveConfig: liveConfigStats,","sourceCodeStart":719,"sourceCodeEnd":755,"githubUrl":"https://github.com/withastro/astro/blob/e294953aa8aadd98d5be92e60a03037b05dbdfd4/packages/astro/src/content/utils.ts#L719-L755","documentation":"Astro 5 moved the content config from src/content/config.ts to src/content.config.ts and requires every collection to declare a loader. When getContentPaths finds only the legacy file and the legacy.collectionsBackwardsCompat flag is not enabled, it throws this error instructing you to migrate.","triggerScenarios":"Upgrading a project to Astro 5+ while src/content/config.ts (or .mjs) still exists; scaffolding a new project by copying an Astro 4-era layout; the modern config file missing so the legacy one is detected.","commonSituations":"astro upgrade from v3/v4; CI failing after a major bump; following tutorials or templates predating Astro 5.","solutions":["Move src/content/config.ts to src/content.config.ts (in src/, not inside src/content/) and give each collection a loader such as glob().","As a temporary bridge, set legacy: { collectionsBackwardsCompat: true } in astro.config.mjs.","Delete the legacy file after migrating so only the new config is found."],"exampleFix":"// before: src/content/config.ts (Astro <=4)\nimport { defineCollection } from 'astro:content';\nconst blog = defineCollection({ schema: z.object({ title: z.string() }) });\nexport const collections = { blog };\n\n// after: src/content.config.ts\nimport { defineCollection, glob } from 'astro/loaders';\nconst blog = defineCollection({\n  loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),\n  schema: z.object({ title: z.string() }),\n});\nexport const collections = { blog };","handlingStrategy":"validation","validationCode":"// Migration guard: fail with a clear message if only the legacy config exists\nimport { existsSync } from 'node:fs';\nconst modern = 'src/content.config.ts';\nconst legacy = 'src/content/config.ts';\nif (!existsSync(modern) && existsSync(legacy)) {\n  throw new Error('Run the Astro 5 migration: move src/content/config.ts to src/content.config.ts');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After upgrading Astro majors, run astro upgrade and read the migration guide for content collections.","Ensure every migrated collection declares a loader (glob(), file(), or custom).","Delete the legacy file once migrated so both configs never compete.","Use legacy.collectionsBackwardsCompat only as a temporary bridge."],"tags":["content-config","migration","astro-5","breaking-change","configuration"],"backgroundTag":"breaking-change-migration","analyzedSha":"e294953aa8aadd98d5be92e60a03037b05dbdfd4","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}