Configuration

CarvePress loads carve-press.config.ts, .js, or .mjs from the project root. Use defineConfig for TypeScript help.

carve-press.config.ts
import { defineConfig } from '@markup-carve/carve-press'

export default defineConfig({
  title: 'Docs',
  srcDir: 'docs',
})

Site Keys

KeyTypeDefaultExample
titlestringrequired'CarvePress'
descriptionstringundefined'Carve-native docs'
hostnamestringundefined'https://example.com'
basestring'/''/carve-press/'
srcDirstring'docs''docs'
outDirstring'dist''.site'
publicDirstring'public''docs/public'
srcExcludestring[][]['drafts/**']
cleanUrlsbooleantruefalse
ignoreDeadLinksbooleanfalsetrue
routeManifeststring | false'routes.json''state/routes.json'
head[string, Record<string, string>][][][['meta', { name: 'theme-color', content: '#111827' }]]
redirectsRecord<string, string>{}{ '/old/': '/new/' }
robotsboolean \| { sitemap?: string \| false }true{ sitemap: 'map.xml' }
substitutionsRecord<string, string \| { value, format }>{}{ minnode: '20' }
assets{ hash?: boolean }{ hash: true }{ hash: false }
rewritesRecord<string, string>{}{ 'pkg/a/docs/*': '/a/*' }
islandsRecord<string, string \| { module, hydrate }>{}{ counter: 'islands/counter.js' }
layoutsRecord<string, Layout>{}{ landing: myLayout }
localesRecord<string, LocaleConfig>{}{ '/de/': { lang: 'de-DE', label: 'Deutsch' } }
dev.incrementalbooleanfalsetrue

dev.incremental is only used by carve-press dev. When enabled, the dev server can reuse a page render if that page’s source, included files, config fingerprint, theme CSS, and installed engine versions are unchanged. Static carve-press build always renders every page so a stale cache can never reach published output.

Theme

KeyTypeDefaultExample
theme.cssstringbuilt-in theme'theme.css'
theme.extraCssstring[]undefined['docs/public/site.css']
themeConfig.navNavItem[][][{ text: 'Guide', link: '/guide/getting-started' }]
themeConfig.sidebarRecord<string, SidebarConfigGroup[]>{}{ '/guide/': [{ text: 'Guide', items: [] }] }
themeConfig.socialLinksSocialLink[][][{ icon: 'github', link: 'https://github.com/markup-carve/carve-press' }]
themeConfig.logostring | { light: string; dark: string; alt?: string }undefined'/logo.svg'
themeConfig.siteTitlestring | falsesite titlefalse
themeConfig.editLink{ pattern: string; text: string }undefined{ pattern: 'https://github.com/org/repo/edit/main/docs/:path', text: 'Edit' }
themeConfig.footer{ message: string; copyright: string }undefined{ message: 'Built with CarvePress', copyright: 'MIT' }
themeConfig.lastUpdatedbooleanundefinedtrue
themeConfig.socialImagestringundefined'/social.png'
themeConfig.outline{ level: [number, number] }{ level: [2, 3] }{ level: [2, 4] }
themeConfig.labelsPartial<ThemeLabels>English labels{ search: 'Search' }

Generated sidebar groups use generate: '/prefix/'; hand-written groups use items. See Theme.

Carve And Shiki

KeyTypeDefaultExample
carve.extensionsCarveExtension[][][myExtension()]
carve.profile'full' | 'article' | 'comment' | 'minimal' | Profileundefined'full'
carve.preset'minimal' | 'docs' | 'full''docs''full'
shiki.langs(string | LanguageRegistration)[]built-in list plus Carve grammar['tsx']
shiki.themes.lightstring'github-light''github-light'
shiki.themes.darkstring'github-dark''github-dark'
shiki.lineNumbersboolean | numberfalsetrue

Search, Blog, Feed

KeyTypeDefaultExample
searchfalse | SearchIndexOptions{ filename: 'search-index.json', exclude: [] }{ exclude: ['/404'] }
blog.dirstringrequired when blog is set'blog'
blog.routestringroute from dir'/blog/'
blog.titlestring'Blog''News'
blog.descriptionstring'''Project updates'
blog.perPagenumber1020
blog.tagsRoutestringblog.route + 'tags/''/blog/tags/'
feedfalse | FeedOptionsfalse{ filename: 'feed.xml' }
feed.filenamestring'feed.xml''atom.xml'
feed.titlestring'''Docs Blog'
feed.descriptionstring'''Updates'
feed.limitnumber2010
feed.type'rss' | 'atom''rss''atom'
extensionsSiteExtension[]built from blog, search, feed, redirects, then user extensions[sitemap({ hostname: 'https://example.com' })]

Locale Config

KeyTypeDefaultExample
langstringrequired'en-US'
labelstringrequired'English'
titlestringsite title'CarvePress DE'
descriptionstringsite description'Lokalisierte Docs'
themeConfig.navNavItem[]root nav[{ text: 'Start', link: '/de/' }]
themeConfig.sidebarRecord<string, SidebarConfigGroup[]>root sidebar{ '/de/': [{ text: 'Guide', items: [] }] }
themeConfig.footerfooter objectroot footer{ message: '...', copyright: '...' }
themeConfig.editLinkedit-link objectroot edit link{ pattern: '...', text: 'Bearbeiten' }
themeConfig.outline{ level: false | number | [number, number] | 'deep' }root outline{ level: 'deep' }
themeConfig.labelsPartial<ThemeLabels>root labels{ search: 'Suchen' }
Edit this page

Last updated