withastro/astro · error · AstroUserError

Live content collections must be defined in "src/live.config

Error message

Live content collections must be defined in "src/live.config.ts" file. Check the loaders used in "${importerFilename}" to ensure you are not using a live loader to define a build-time content collection.

What it means

When `defineCollection` is given an object `loader` that lacks a `load` function but exposes `loadEntry`/`loadCollection`, Astro treats it as a live loader placed in a build-time config file — a category error. Live loaders belong in `src/live.config.ts`; build-time loaders (with `load`) belong in `src/content/config.ts`.

Source

Thrown at packages/astro/src/content/config.ts:203

			message: AstroErrorData.LiveContentConfigError.message(
				'Collections in a live config file must use `defineLiveCollection`.',
				importerFilename,
			),
		});
	}

	if ('loader' in config) {
		if (config.type && config.type !== CONTENT_LAYER_TYPE) {
			throw new AstroUserError(
				`A content collection is defined with legacy features (e.g. missing a \`loader\` or has a \`type\`). Check your collection definitions in ${importerFilename ?? 'your content config file'} to ensure that all collections are defined using the current properties.`,
			);
		}
		if (
			typeof config.loader === 'object' &&
			typeof config.loader.load !== 'function' &&
			('loadEntry' in config.loader || 'loadCollection' in config.loader)
		) {
			throw new AstroUserError(
				`Live content collections must be defined in "src/live.config.ts" file. Check the loaders used in "${importerFilename ?? 'your content config file'}" to ensure you are not using a live loader to define a build-time content collection.`,
			);
		}
		config.type = CONTENT_LAYER_TYPE;
	}
	if (!config.type) config.type = 'content';
	return config;
}

View on GitHub (pinned to d081033d5f)

Solutions

  1. Move the collection to `src/live.config.ts` and define it via `defineLiveCollection`.
  2. Or swap the loader for a build-time loader (`load`-based) such as `glob()` or `file()`.
  3. Confirm whether the loader you imported is a live or build-time loader from its package docs.

Example fix

// before — src/content/config.ts
import { myLiveLoader } from 'some-integration/live';
export const collections = { cms: defineCollection({ loader: myLiveLoader() }) };
// after — src/live.config.ts
import { defineLiveCollection } from 'astro:content';
import { myLiveLoader } from 'some-integration/live';
export const collections = { cms: defineLiveCollection({ loader: myLiveLoader() }) };
Defensive patterns

Strategy: validation

Validate before calling

if (typeof config.loader === 'object' && typeof config.loader.load !== 'function' && ('loadEntry' in config.loader || 'loadCollection' in config.loader)) {
  throw new Error('This is a live loader — move it to src/live.config.ts');
}

Type guard

function isBuildLoader(l) { return !!l && typeof l.load === 'function'; }

Prevention

When it happens

Trigger: Passing a live loader (object with `loadEntry`/`loadCollection` but no `load`) to `defineCollection` inside `src/content/config.ts`.

Common situations: Using a live loader integration (e.g. a CMS live loader) inside the build-time config; mixing up which config file is which after renaming.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/7eadecf7844832cb. Report an issue: GitHub.