withastro/astro · warning

[astro] ${names} ${isPlural ? 'are' : 'is'} deprecated. Move

Error message

[astro] ${names} ${isPlural ? 'are' : 'is'} deprecated. Move ${isPlural ? 'them' : 'it'} onto your processor instead (e.g. `satteri({ features: { gfm: false, smartPunctuation: false } })`, or `unified({ gfm: false, smartypants: false })` from `@astrojs/markdown-remark`). Will be removed in a future major.

What it means

The top-level markdown.gfm and markdown.smartypants options are deprecated; they are only mapped onto the markdown processor's feature flags. When either key is set (any value other than undefined), Astro warns once (module-level flag) and points you at configuring the processor directly via unified({ features: ... }) or satteri({ features: ... }) from @astrojs/markdown-remark.

Source

Thrown at packages/astro/src/core/config/validate.ts:46

		}),
	);
}

let didWarnAboutDeprecatedMarkdownOptions = false;

function warnDeprecatedMarkdownOptions(
	config: Pick<AstroUserConfig, 'markdown'> | undefined,
): void {
	if (didWarnAboutDeprecatedMarkdownOptions) return;
	const md = config?.markdown;
	if (!md) return;
	const deprecated = (['gfm', 'smartypants'] as const).filter((k) => md[k] !== undefined);
	if (deprecated.length === 0) return;
	didWarnAboutDeprecatedMarkdownOptions = true;

	const names = deprecated.map((key) => `\`markdown.${key}\``).join(' and ');
	const isPlural = deprecated.length > 1;
	console.warn(
		`[astro] ${names} ${isPlural ? 'are' : 'is'} deprecated. Move ${isPlural ? 'them' : 'it'} onto your processor instead (e.g. \`satteri({ features: { gfm: false, smartPunctuation: false } })\`, or \`unified({ gfm: false, smartypants: false })\` from \`@astrojs/markdown-remark\`). Will be removed in a future major.`,
	);
}

let didWarnAboutLegacyMarkdownPlugins = false;
let didWarnAboutProcessorMismatch = false;

const migratedLegacyPluginCounts = new WeakMap<object, { remark: number; rehype: number }>();
/**
 * Folds legacy `markdown.{remark,rehype}Plugins` / `remarkRehype` into the unified
 * processor (mutates `config`). Runs on every validate pass to catch integration-added
 * legacy plugins.
 */
async function coerceLegacyMarkdownPlugins(
	config: Pick<AstroUserConfig, 'markdown'>,
): Promise<void> {
	const md = config?.markdown;
	if (!md) return;

View on GitHub (pinned to 52e6c34790)

Solutions

  1. Remove markdown.gfm / markdown.smartypants from the config
  2. Configure features on the processor: markdown: { processor: unified({ features: { gfm: false, smartPunctuation: false } }) }
  3. If you only wanted the default behavior, simply delete the keys

Example fix

// before — astro.config.mjs
export default defineConfig({
  markdown: { gfm: false, smartypants: false },
});

// after
import { unified } from '@astrojs/markdown-remark';
export default defineConfig({
  markdown: {
    processor: unified({ features: { gfm: false, smartPunctuation: false } }),
  },
});
Defensive patterns

Strategy: validation

Validate before calling

// fail CI when deprecated markdown option keys are present
const deprecated = ['gfm', 'smartypants', 'remarkPlugins', 'rehypePlugins', 'remarkRehype'];
const present = deprecated.filter((k) => config.markdown?.[k] !== undefined);
if (present.length) throw new Error(`Deprecated markdown options: ${present.join(', ')}`);

Prevention

When it happens

Trigger: astro.config contains markdown: { gfm: ... } and/or markdown: { smartypants: ... } with any explicit value — including explicitly re-setting the defaults.

Common situations: Long-standing configs carried over from Astro v4 and earlier; disabling smartypants or gfm the old way; integration code that mutates the markdown config with these keys.

Related errors


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