withastro/astro · warning

${colors.bold(plugin)} not applied.

Error message

${colors.bold(plugin)} not applied.

What it means

The MDX integration drops any markdown plugin passed as a plain string (e.g. 'remark-gfm') from the markdown config it inherits. MDX compiles through its own Vite/esbuild pipeline, which can only use actual imported plugin functions, so string plugin names are filtered out by ignoreStringPlugins() with this warning. The plugin silently does not run for .mdx files while still working for .md files.

Source

Thrown at packages/integrations/mdx/src/utils.ts:93

		type: 'mdxjsEsm',
		value: '',
		data: {
			// @ts-expect-error `parse` return types is incompatible but it should work in runtime
			estree: {
				...parse(jsString, acornOpts),
				type: 'Program',
				sourceType: 'module',
			},
		},
	};
}

export function ignoreStringPlugins(plugins: any[], logger: AstroIntegrationLogger): PluggableList {
	let validPlugins: PluggableList = [];
	let hasInvalidPlugin = false;
	for (const plugin of plugins) {
		if (typeof plugin === 'string') {
			logger.warn(`${colors.bold(plugin)} not applied.`);
			hasInvalidPlugin = true;
		} else if (Array.isArray(plugin) && typeof plugin[0] === 'string') {
			logger.warn(`${colors.bold(plugin[0])} not applied.`);
			hasInvalidPlugin = true;
		} else {
			validPlugins.push(plugin);
		}
	}
	if (hasInvalidPlugin) {
		logger.warn(
			`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`,
		);
	}
	return validPlugins;
}

View on GitHub (pinned to 52e6c34790)

Solutions

  1. Import the plugin and pass the function instead of the name: import remarkGfm from 'remark-gfm' then remarkPlugins: [remarkGfm].
  2. For tuple plugins, import the function too: import rehypeExternalLinks from 'rehype-external-links' then rehypePlugins: [[rehypeExternalLinks, { target: '_blank' }]].
  3. Keep syntax-highlighter style string options separate; only remarkPlugins/rehypePlugins need function references.
  4. Rebuild after config changes (pnpm build) and confirm the warning no longer prints during 'astro:config:setup' for MDX.

Example fix

// before (astro.config.mjs)
export default defineConfig({
  markdown: { remarkPlugins: ['remark-gfm'] },
  integrations: [mdx()],
});

// after
import remarkGfm from 'remark-gfm';
export default defineConfig({
  markdown: { remarkPlugins: [remarkGfm] },
  integrations: [mdx()],
});
Defensive patterns

Strategy: type-guard

Validate before calling

const isPluginRef = (p: unknown): boolean =>
  typeof p === 'function' || (Array.isArray(p) && typeof p[0] === 'function');
const allValid = config.markdown.remarkPlugins.every(isPluginRef) &&
  config.markdown.rehypePlugins.every(isPluginRef);

Type guard

type PluginRef = unknown;
const isPluginRef = (p: PluginRef): p is ((...a: any[]) => any) | [(...a: any[]) => any, any] =>
  typeof p === 'function' || (Array.isArray(p) && typeof p[0] === 'function');

Prevention

When it happens

Trigger: astro.config.mjs sets markdown.remarkPlugins or markdown.rehypePlugins to an array containing a bare string, e.g. remarkPlugins: ['remark-gfm'], while the @astrojs/mdx integration is installed. MDX reads config.markdown plugins during astro:config:setup and hits the typeof plugin === 'string' branch of ignoreStringPlugins().

Common situations: Copying an older Astro v1-era config or a blog tutorial that registered plugins by name; sharing one markdown config between Astro and another tool (e.g. Eleventy or eslint-plugin-markdown) that accepts strings; passing tuples like ['rehype-external-links', {target:'_blank'}] where the first element is a string.

Related errors


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