Valkyrian Labs logo

Installation

Install the package and register Payload Markdown in Payload config.

Installation

Install the package in the Payload app:

1pnpm add payload-markdown
Install the agent skill

If you use Payload MCP or let AI agents such as Claude Code or Codex work in your repo, install the skill that ships with the package. It teaches agents every directive, theme and the MCP content workflow.

1npx payload-markdown skill install

Run it again after upgrading the package. See Agent Skill for drift checks and options.

Package Names

The package is published under two names from the same build, always at the same version:

PackageInstall
payload-markdownpnpm add payload-markdown
@valkyrianlabs/payload-markdownpnpm add @valkyrianlabs/payload-markdown

Both are fully supported and behave identically. Import from the name you installed: these docs use payload-markdown, so with the scoped package write @valkyrianlabs/payload-markdown/server instead of payload-markdown/server, and so on. The Payload admin components follow whichever name is installed, so the import map needs no extra configuration.

Switching an existing app from one name to the other: replace the dependency and the imports, update the Tailwind @source path, then run payload generate:importmap so the admin import map points at the new name.

Install one name

Installing both names loads two copies of the plugin. Pick one per app.

Register The Plugin

Add payloadMarkdown() to the Payload plugins array.

1import { payloadMarkdown } from 'payload-markdown'2import type { Config } from 'payload'3 4const config: Config = {5  plugins: [6    payloadMarkdown({7      collections: {8        posts: true,9      },10    }),11  ],12}13 14export default config

When a collection is enabled with true, the plugin infers the useful install path:

  • collections without a blocks field receive a Markdown text field named content
  • collections with one or more blocks fields receive the vlMdBlock Markdown block inside those fields
The plugin avoids duplicates

If a collection already has a field with the target name, the plugin does not add another one. If the root Payload config or a blocks field already includes vlMdBlock, it is not added twice.

Configure A Collection Explicitly

Use an object when you want to choose the field name, field options, or install behavior.

1payloadMarkdown({2  collections: {3    posts: {4      fieldName: 'body',5      field: {6        admin: {7          description: 'Author-facing Markdown body',8        },9        defaultValue: '# Draft',10        label: 'Body Markdown',11        localized: true,12        required: true,13      },14      installField: true,15      installIntoBlocks: false,16    },17  },18})

Preferred Config Shape

Keep each concern in its own namespace:

1import { DEFAULT_CODE_LANGS, payloadMarkdown } from 'payload-markdown'2 3payloadMarkdown({4  code: {5    enhanced: true,6    fullBleed: false,7    langs: [...DEFAULT_CODE_LANGS, 'latex', 'r'],8    lineNumbers: true,9    shikiTheme: 'github-dark',10  },11  config: {12    size: 'lg',13    variant: 'blog',14  },15  themes: {16    card: {17      items: [18        {19          name: 'feature',20          classes: 'rounded-2xl border border-cyan-400/40 bg-cyan-950/30 p-5',21        },22      ],23    },24  },25  collections: {26    posts: {27      code: {28        lineNumbers: false,29      },30      config: {31        variant: 'docs',32      },33      themes: {34        callout: {35          items: [36            {37              name: 'editorial',38              classes: 'rounded-xl border border-white/10 bg-white/5 px-4 py-3',39            },40          ],41        },42      },43    },44  },45})

Use code, not config.options, for Shiki and code fence behavior. Use themes, not config.themes, for directive theme registries.

Tailwind Setup

The renderer uses Tailwind-friendly class strings. For the default typography layer, install and enable Tailwind Typography:

1pnpm add @tailwindcss/typography
1@import "tailwindcss";2@plugin "@tailwindcss/typography";3 4@source "../node_modules/payload-markdown/dist";

Installed the scoped package? Point @source at ../node_modules/@valkyrianlabs/payload-markdown/dist instead.

Keep custom directive theme class strings in source-controlled config so Tailwind can discover them. Markdown authors should select named themes with theme="..." rather than writing arbitrary Tailwind classes in CMS content.