withastro/astro · warning

${names} on `mdx({...})` ${isPlural ? 'are' : 'is'} deprecat

Error message

${names} on `mdx({...})` ${isPlural ? 'are' : 'is'} deprecated. Pass ${isPlural ? 'them' : 'it'} to `unified({...})` from `@astrojs/markdown-remark` and set it as `markdown.processor` instead — MDX will inherit ${isPlural ? 'them' : 'it'}. Will be removed in a future major.

What it means

Passing remarkPlugins, rehypePlugins, or remarkRehype directly to mdx() is deprecated: the integration detects any of the three keys and warns once per process (didWarnAboutDeprecatedMdxPluginOptions). Markdown/MDX option handling was consolidated into the unified() helper exported by @astrojs/markdown-remark — configure the options there and assign the result to markdown.processor in astro.config; MDX inherits that processor's configuration.

Source

Thrown at packages/integrations/mdx/src/index.ts:287

		};
	}
	return {};
}

let didWarnAboutDeprecatedMdxPluginOptions = false;

function warnDeprecatedMdxPluginOptions(
	options: Partial<MdxOptions>,
	logger: AstroIntegrationLogger,
): void {
	if (didWarnAboutDeprecatedMdxPluginOptions) return;
	const deprecated = LEGACY_PLUGIN_OPTIONS.filter((key) => options[key] !== undefined);
	if (deprecated.length === 0) return;
	didWarnAboutDeprecatedMdxPluginOptions = true;

	const names = deprecated.map((key) => `\`${key}\``).join(', ');
	const isPlural = deprecated.length > 1;
	logger.warn(
		`${names} on \`mdx({...})\` ${isPlural ? 'are' : 'is'} deprecated. ` +
			`Pass ${isPlural ? 'them' : 'it'} to \`unified({...})\` from \`@astrojs/markdown-remark\` ` +
			`and set it as \`markdown.processor\` instead — MDX will inherit ${isPlural ? 'them' : 'it'}. ` +
			'Will be removed in a future major.',
	);
}

function applyDefaultOptions({
	options,
	defaults,
}: {
	options: Partial<MdxOptions>;
	defaults: ResolvedMdxOptions;
}): ResolvedMdxOptions {
	return {
		syntaxHighlight: options.syntaxHighlight ?? defaults.syntaxHighlight,
		shikiConfig: options.shikiConfig ?? defaults.shikiConfig,
		gfm: options.gfm ?? defaults.gfm,

View on GitHub (pinned to e294953aa8)

Solutions

  1. Import { unified } from '@astrojs/markdown-remark' and pass the plugin options to it
  2. Assign the result to markdown.processor in astro.config: markdown: { processor: unified({ remarkPlugins, rehypePlugins }) }
  3. Remove the deprecated keys from mdx({...}) so configuration has a single source of truth
  4. Rebuild and confirm MDX output still applies the plugins (they are inherited through the shared processor)

Example fix

// before
import mdx from '@astrojs/mdx';
export default defineConfig({
  integrations: [mdx({ remarkPlugins: [pluginA], rehypePlugins: [pluginB] })],
});

// after
import mdx from '@astrojs/mdx';
import { unified } from '@astrojs/markdown-remark';
export default defineConfig({
  markdown: { processor: unified({ remarkPlugins: [pluginA], rehypePlugins: [pluginB] }) },
  integrations: [mdx()],
});
Defensive patterns

Strategy: validation

Validate before calling

// Guard in astro.config.mjs: reject deprecated mdx() options at load time
const mdxOptions: Record<string, unknown> = {};
for (const k of ['remarkPlugins', 'rehypePlugins', 'remarkRehype']) {
  if (k in mdxOptions) throw new Error(`mdx({ ${k} }) is deprecated — use markdown.processor via unified()`);
}

Prevention

When it happens

Trigger: `integrations: [mdx({ remarkPlugins: [...], rehypePlugins: [...] })]` (or remarkRehype) in astro.config.mjs. Any one of the three keys being present triggers the single warning, no matter what values they hold.

Common situations: Long-standing configs predating the processor unification; adding a remark/rehype plugin intended for MDX and placing it in the integration options; upgrading @astrojs/mdx and @astrojs/markdown-remark majors together.

Related errors


AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18). Data as JSON: /api/errors/30ed712eb5d90ab5. Report an issue: GitHub.