# Vellum > Markdown documentation sites that ship with your Laravel app. ================================================================================ Title: Vellum URL: https://vellum.jimmyverburgt.com/docs ================================================================================ --- title: Vellum description: Markdown documentation sites that ship with your Laravel app. --- Vellum serves a folder of Markdown as a documentation site from the Laravel app you already deploy. It includes a sidebar, search, light and dark themes, and an optional static export. You write pages in Markdown. The built-in callouts, tabs, steps and cards use `:::` directives, and `` tags add your own Blade components and the allowlisted `env`, `config` and `route` value tags. Blade syntax such as `{{ }}`, `@if` and `@php` is not compiled in Markdown files. :::note `config/vellum.php` keys and page frontmatter have been frozen since 0.5. Breaking changes wait for 1.0. ::: :::steps ## Require the package `composer require jimmyverburgt/vellum` ## Publish stubs `php artisan vellum:install` ## Open the site Visit `/docs` and edit `resources/docs/`. ::: :::cards describe="pages" ::card[What is Vellum](/docs/why) ::card[Installation](/docs/getting-started/installation) ::card[Writing Markdown](/docs/writing/markdown) ::card[Components](/docs/components) ::card[Navigation](/docs/writing/navigation) ::card[Extending](/docs/extending) ::: ================================================================================ Title: What is Vellum URL: https://vellum.jimmyverburgt.com/docs/why ================================================================================ --- title: What is Vellum description: A Laravel package that serves a folder of Markdown as a documentation site from your app, or exports it as a static site. --- Vellum is a Laravel package that turns a folder of Markdown into a documentation site. The Markdown lives in your application's repository, `php artisan vellum:build` compiles it during deploy, and your app serves it at `/docs`. The same files can also be exported as a static site for a host that does not run PHP. ## What you get - A sidebar built from your folders, ordered with `meta.json` or frontmatter - In-browser search filtered for each reader, or Laravel Scout - Light and dark mode, three colour presets and an accent colour - Callouts, tabs, steps and cards as `:::` directives, and your own Blade components - Code highlighted on the server, with titles, line numbers and highlighted lines - Version folders and a changelog page with an Atom feed - Access control per page or folder, for signed-in readers or through a Laravel gate - Value tags that print allowlisted `env`, `config` and route values - Raw Markdown for every page, a copy button, and links that open the page in ChatGPT or Claude - A sitemap, canonical links and Open Graph tags - Link, image and heading checks at build time ## How it works `vellum:build` compiles each page to a PHP file and writes the navigation and search index. Laravel serves the pages from a route like any other, so requests do not parse Markdown. The CSS and JavaScript ship precompiled with the package, so you install Vellum with Composer alone. `vellum:export` writes the same site as static HTML, with its assets and a search index. The export differs from the served site in two ways: value tags keep the values they had at export time, and gated pages are left out because a static host has no session to check access against. ## What it does not do - **Edit in the browser.** Pages are Markdown files in your repository, changed through pull requests. - **Analytics or AI chat.** There is no hosted service behind Vellum. - **Design a custom front end for you.** The site's layout is a fixed docs theme, though you can override any of its Blade views. To render the docs in a front end of your own, use [core on its own](/docs/core). - **Run outside Laravel.** It needs a Laravel app to build in, even when you only use the static export. ## Stability The current release is 0.8. Config keys, frontmatter and the authoring syntax have been frozen since 0.5. Later releases add to them without renaming anything, and breaking changes wait for 1.0. [Upgrade](/docs/getting-started/upgrade) lists what changed between releases. [Installation](/docs/getting-started/installation) takes about five minutes. [Comparisons](/docs/comparisons) covers how Vellum differs from LaRecipe. ================================================================================ Title: Comparisons URL: https://vellum.jimmyverburgt.com/docs/comparisons ================================================================================ --- title: Comparisons description: How Vellum differs from LaRecipe, the other package that serves Markdown documentation from inside a Laravel app. --- ## LaRecipe [LaRecipe](https://github.com/saleem-hadad/larecipe) is the closest alternative to Vellum. It is also a Laravel package that serves Markdown from `resources/docs` at `/docs`. It dates from 2018 and is still maintained. The table compares both packages as of September 2026. | | Vellum | LaRecipe | | --- | --- | --- | | Rendering | Compiled once by `vellum:build` | Parsed on each request, with an optional cache | | Markdown | CommonMark and GitHub Flavored Markdown | Parsedown Extra | | Sidebar | Your folder structure, ordered by `meta.json` or frontmatter | A hand-written `index.md` per version | | Access control | Per page or folder: signed-in readers or a named gate, hidden pages return 404 | The whole site, behind a guard or your own middleware | | Search | Built in, in the browser, filtered per reader. Laravel Scout optional | Algolia, or a built-in index of `h2` and `h3` headings | | Static export | Yes | No | | Front end | Alpine.js, compiled assets included | Vue | | Dark mode | Built in | A separate package | | Components | `:::` directives and Blade components | Blade, and Vue components through asset packages | | Requirements | PHP 8.4, Laravel 11 to 13 | PHP 7.1 or later, Laravel 5.4 to 13 | Choose LaRecipe if you are on an older PHP or Laravel version, or if you want one of its add-on packages for Swagger, right-to-left layouts, reader feedback or Disqus comments. Choose Vellum if some pages should only be visible to certain readers, if you also want a static copy of the docs, or if you want broken links caught before a deploy. ## Outside Laravel If your product is not a Laravel app, use a documentation framework built for its stack, such as [Fumadocs](https://fumadocs.dev) for Next.js or [VitePress](https://vitepress.dev) for a standalone static site. Vellum's layout is based on Fumadocs, and the [credits](/docs/credits) list what it borrows. ================================================================================ Title: Installation URL: https://vellum.jimmyverburgt.com/docs/getting-started/installation ================================================================================ --- title: Installation description: Requirements, installing the package, and the build step for production. --- ## Requirements - PHP 8.4+ - Laravel 11, 12, or 13 ## Install :::steps ## Require the package ```bash composer require jimmyverburgt/vellum ``` This installs the docs site and `jimmyverburgt/vellum-core`, the engine it runs on. To render the docs in your own front end instead, see [Core on its own](/docs/core). ## Publish config, stubs, and assets ```bash php artisan vellum:install ``` `vellum:install` publishes `config/vellum.php`, copies starter Markdown into `resources/docs` and copies the compiled CSS and JavaScript to `public/vendor/vellum`. ## Open the site Visit `/docs`, then edit the files in `resources/docs/`. ::: ## Production Compile the Markdown once per deploy: ```bash php artisan vellum:build ``` In the `local` environment pages recompile on request as you edit them, so you only need this command in your deploy. See [Commands](/docs/commands). ## Next - [Markdown](/docs/writing/markdown) for the Markdown syntax Vellum renders - [Navigation](/docs/writing/navigation) to arrange the sidebar - [Configuration](/docs/getting-started/configuration) for every config key and frontmatter field - [Commands](/docs/commands) for what to run in a deploy - [Upgrade](/docs/getting-started/upgrade) if you are upgrading from an earlier version - [Troubleshooting](/docs/troubleshooting) when a page does not render ================================================================================ Title: Configuration URL: https://vellum.jimmyverburgt.com/docs/getting-started/configuration ================================================================================ --- title: Configuration description: Every config key and frontmatter field, all frozen since 0.5. --- `vellum:install` publishes the config to `config/vellum.php`. The key names have been frozen since 0.5. Later releases can add keys, but none will be renamed before 1.0. ## Site and routing | Key | Default | Purpose | | --- | --- | --- | | `name` | `env('APP_NAME', 'Docs')` | Site name, shown in the header and page titles | | `path` | `env('VELLUM_PATH', resource_path('docs'))` | Root folder of the Markdown files. A relative path is read from the app root | | `route.prefix` | `docs` | URL prefix | | `route.middleware` | `['web']` | Route middleware | | `route.domain` | `null` | Optional domain for the docs routes. Canonical links and the sitemap use it as their host, with the scheme from `app.url` | | `repo` | `null` | Base URL for the "Edit on GitHub" link | | `logo` | `null` | Path to an SVG file, or a Blade view name, for the site logo | | `links` | `[]` | Extra links, each with `label`, `href` and an optional `icon: github`. Shown in the sidebar footer, or in the header when `layout.search` is `header` | | `layout.search` | `env('VELLUM_LAYOUT_SEARCH', 'sidebar')` | Where the search field sits: `sidebar` or `header`. See [Theming](/docs/theming#where-search-sits) | | `layout.toc` | `env('VELLUM_LAYOUT_TOC', 'window')` | How the table of contents marks what is on screen: `window` or `line`. See [Theming](/docs/theming#table-of-contents) | | `fonts` | `null` | HTML added to the layout's head, such as a font stylesheet link | | `checks.references` | `true` | Warn during `vellum:build` about links and images that point at nothing | | `checks.strict` | `false` | Fail the build when there are reference warnings | | `checks.search` | `true` | Ask the questions in `questions.yml`, if the docs have one, during `vellum:build`. See [Search](/docs/search#checking-search-in-ci) | | `checks.search_min` | `env('VELLUM_SEARCH_MIN', 0.0)` | The share of those questions that must find their answer for the build to pass. `0` reports without failing | | `agents.llms_txt` | `true` | Serve `llms.txt` and `llms-full.txt` under the docs prefix. See [Page actions](/docs/page-actions#for-agents) | | `agents.llms_txt_root` | `true` | Also serve both at `/llms.txt` and `/llms-full.txt`, unless the app already routes those paths | | `agents.content_negotiation` | `true` | Serve a page's raw Markdown when the request's `Accept` header prefers `text/markdown` | | `agents.search` | `true` | Serve `{prefix}/_vellum/search?q=`, which returns search results as JSON. See [Search](/docs/search#the-search-endpoint) | | `cache.path` | `storage_path('framework/vellum')` | Directory for compiled pages | | `export.out` | `public_path('docs-static')` | Output directory for `vellum:export` | | `export.base_url` | `/` | URL prefix used inside the export | ## Theme See [Theming](/docs/theming) for the presets, the accent colour and the contrast target. ```php 'theme' => [ 'preset' => 'neutral', 'primary' => null, 'accent' => null, 'radius' => '0.5rem', 'default' => 'system', ], ``` ## Versions See [Versions](/docs/versions). ```php 'versions' => [ 'enabled' => false, 'latest' => 'v2', 'list' => ['v2', 'v1'], 'labels' => [], ], ``` ## Search See [Search](/docs/search). ```php 'search' => [ 'enabled' => true, 'hotkey' => 'k', 'driver' => env('VELLUM_SEARCH_DRIVER', 'builtin'), 'scout' => [ 'index' => 'vellum', ], ], ``` ## Components See [Value tags](/docs/value-tags) and [Extending](/docs/extending). ```php 'components' => [ 'namespaces' => ['vellum'], 'allowlist' => [ 'env' => [], 'config' => [], 'route' => [], ], ], ``` ## Changelog See [Release notes](/docs/releases). ```php 'changelog' => [ 'path' => env('VELLUM_CHANGELOG', base_path('CHANGELOG.md')), 'unreleased' => false, ], ``` ## Frontmatter Pages accept these frontmatter keys, which are also frozen: | Key | Purpose | | --- | --- | | `title` | Page title. Falls back to the first heading, then the file name | | `description` | Meta description, also shown on the next-page card and on cards that ask for it | | `slug` | Overrides the URL slug | | `order` | Position among sibling pages when `meta.json` does not list them | | `full` | Hides the table of contents column | | `access` | `guest`, `auth`, or a gate name. See [Gating](/docs/gating). | | `updated` | Last-updated date, `2026-09-17` or ISO 8601 (`2026-09-17T10:00:00+02:00`), shown under the page title. Without it, the file's last git commit date is used, when the docs are in a full git clone. File modification times are never used | | `questions` | Questions the page answers, as a list. Search matches a reader's question against them, alongside the ones Vellum derives from headings, commands and config keys | | `aliases` | Other names readers use for the page's subject, as a list. A search containing one also matches the page title and the other aliases | A folder's `meta.json` accepts `title`, `defaultOpen`, `pages` and `access`. A `_meta.md` file can set the folder's `access` or title in frontmatter instead. See [Navigation](/docs/writing/navigation). Unknown keys are stored but ignored. Do not treat that behaviour as an API. ================================================================================ Title: Upgrade URL: https://vellum.jimmyverburgt.com/docs/getting-started/upgrade ================================================================================ --- title: Upgrade description: Upgrading from 0.8 to 0.9, from 0.7 to 0.8, from 0.6 to 0.7, within 0.6, from 0.5 to 0.6, and from 0.2 to the 0.5 freeze. --- 0.5 froze the keys in `config/vellum.php` and the page frontmatter names. Later releases add keys without renaming any, and no key will be removed before 1.0. The requirements have been PHP 8.4+ and Laravel 11, 12, or 13 since 0.2. ## 0.8 to 0.9 No changes to your content or config are required. Update the package and rebuild: ```bash composer update jimmyverburgt/vellum php artisan vellum:build ``` 0.9 adds the [API reference](/docs/api-reference). It is off until you set `openapi.enabled`, and a site that leaves it off is served as before. Two fixes change what existing pages look like after the rebuild: - A code block inside a tab, a callout or a step keeps an indent of one to three spaces, which was dropped before. YAML or JSON indented by two now shows as written. - A line of `:::` inside a fenced code block is a line of code. It used to close the directive around the block. ### If you turn the reference on A config file published before 0.9 has no `openapi` array. The package's defaults apply until you add one, so `VELLUM_OPENAPI=true` in `.env` is enough to start. The reference adds a switch between the docs and the reference to the sidebar. If you have published the `sidebar`, `mobile-sidebar`, `header` or `shell` component, or the `doc`, `changelog` or `404` page, your copy does not pass it along and the two sidebars have no way from one to the other. Copy those views again from 0.9, or set `openapi.sidebar` to `docs` to list the reference as a folder of the docs' sidebar instead. ## 0.7 to 0.8 No changes to your content are required. Update the package and rebuild: ```bash composer update jimmyverburgt/vellum php artisan vellum:build ``` The update also installs `jimmyverburgt/vellum-core`, which now holds the engine Vellum runs on. Nothing changes in how you install or use the full package. See [Core on its own](/docs/core) for what core is. Run `vellum:build` even outside a deploy. Compiled pages keep the HTML they were built with, and most components have new markup. On pages compiled by 0.7, the heading buttons stop copying links, the code buttons lose their check mark, and callouts, tabs and cards do not match the new stylesheet until the pages are rebuilt. ### What readers will notice 0.8 redesigns the details of every page, with no change to how you write them. The ones most likely to surprise: - A shell block without a title is shown as a terminal with a `$` before each command. If you typed `$` yourself, it now shows twice, so remove yours. See [Terminal commands](/docs/writing/code-blocks#terminal-commands). - Callouts are no longer boxes, and each names its type on its first line. - The table of contents has a new default style, `window`. See [Table of contents](/docs/theming#table-of-contents) to keep `line`. - With versions on, the switcher shows the latest version by its slug with a "Latest" tag, where it used to say "Latest" alone. Give the version a name in `versions.labels` if the slug is not what readers should see. Pages of any other version start with a notice. See [Versions](/docs/versions). - Corners that ignored `theme.radius` now follow it, so a radius you changed also changes code blocks, tables, tabs and images. ### Config `layout.toc` is new. A config file published before 0.8 has a `layout` array without it, and a published array replaces the package's whole, so `VELLUM_LAYOUT_TOC` is ignored until the key is in your file. Add it, or republish the config: ```php 'layout' => [ 'search' => env('VELLUM_LAYOUT_SEARCH', 'sidebar'), 'toc' => env('VELLUM_LAYOUT_TOC', 'window'), ], ``` `vellum:build` no longer warns about a colour preset removed in 0.5. The site still falls back to `neutral`. ### Views you overrode A view you copied from 0.7 into `resources/views/vendor/vellum/` and changed needs attention: - The sidebar, the layout and every `ui` view named a class that has moved, so a 0.7 copy fails with "Class not found". Change the namespace in your copy, or copy the 0.8 view again. `Vellum\Support\Theme`, `Color`, `Assets`, `Cn` and `NavTree` are now in `Vellum\View`. - A copy of the `callout`, `card`, `step` or `tabs` view has the old markup and will not match the new stylesheet. Copy it again from 0.8. - A component view you published to `resources/views/vendor/vellum/components/` now also applies to the `:::` form of that component, not only the `` tag. See [Change a built-in's markup](/docs/extending#change-a-built-ins-markup). - The page actions moved into the line under the title. An override of `components/docs/page-actions.blade.php` still works, and `components/docs/page-meta.blade.php` is the view for the whole line. ### CSS and scripts that target Vellum's markup - **Callouts:** the glyph is inside `.vellum-callout-title`, which is now always present. The border and background are gone, apart from a tint on warnings and dangers. - **Tabs:** every group is a bordered card. The label row has a `.vellum-tabs-underline` element, and the group a `data-vellum-tabs-sliding` attribute once its script runs. - **Code blocks:** a block without a title, other than a shell block, has no `.vellum-code-header`. Its language is in `.vellum-code-actions > .vellum-code-lang`. Select a kind with `data-vellum-code-kind`, which is `file`, `terminal` or `snippet`. - **Copy buttons:** they are marked `data-vellum-copy-code` and `data-vellum-heading-copy`, without Alpine attributes. - **Cards:** a card is a grid, with a `.vellum-card-arrow` and, when it has one, a `.vellum-card-description`. - **Tables:** cells carry `data-label`. Below 40rem the table, its rows and its cells are `display: block`, and the header row is visually hidden. - **Images:** an image on a line of its own has `data-vellum-image-block`, and its paragraph or figure is a padded, bordered mat. - **Steps:** a step title under a section heading is one level below it, so a step under `## Setup` is an `h3`. The step's number is an ``. - **Previous and next:** the classes are `.vellum-pagination`, `-prev`, `-next`, `-label`, `-title` and `-description`. Previous has no box and no description. - **Last updated:** the `