Site configuration
Every environment variable, config file and generated record of a site built with the kit, with defaults and who may edit each one. For developers.
On this page
A site is configured by a small set of files and environment variables. This page lists all of them. Some you edit, some tools write, and some you must never commit. For the ownership rules behind that, see Ownership zones.
Where settings come from
| Source | Used for |
|---|---|
| Environment variables | Everything below. A variable that is already set in the environment wins over the file. |
.env in the site folder | The same variables for local work. It is read by the kit and by the commands. It is in .gitignore: never commit it. |
.env.example | The documented list of names, without values. Commit it. |
| Pipeline variables and secrets | The same variables in CI. See Deploying a site. |
| App Service settings and Key Vault | Run-time settings of the server or the API. See Azure and Bicep. |
Astro only gives .env to import.meta.env. The kit also loads it into process.env before it runs, so the build, lake.config.ts and the commands see the same values.
Environment variables
The lake
| Variable | Default | Meaning |
|---|---|---|
LAKE_PATH | none | A lake clone you keep by hand. It overrides the managed clone. Without it, a site whose lake.lock has a remote builds from .mdlake/lake, and a site without one builds from ./example-lake. Do not set it in CI. |
MDLAKE_LAKE_TOKEN | none | A read-only token for fetching the lake in CI (fine-grained, Contents: read on the lake repository). Never commit it. See The lake in CI, and caches. |
LAKE_LOCK_CANDIDATE | none | Build and check against this lake commit instead of the locked one. The refresh flow uses it. |
LAKE_LOCK_IGNORE | none | 1 builds even though the lake is not at the locked commit, with a warning. Emergencies only. Never deploy that build. |
The site and its assets
| Variable | Default | Meaning |
|---|---|---|
SITE_URL | https://www.example.com | The public origin. Used for canonical links, the sitemap and social tags. Set it in every environment. |
PUBLIC_ASSET_BASE_URL | none | Where assets are fetched from, as <base>/<asset id>, for example a CDN in front of storage. Without it each asset uses the public url in its sidecar. |
PUBLIC_ASSET_RESIZE | false | true when the asset host resizes with ?w=<width>. Only the dev server and previews use it. A build copies assets and serves them from its own /files/ path. |
ASSET_OPTIMIZE | true | false copies the original images to /files instead of converting them (faster builds, larger pages). It applies only to assets from a remote host. |
SITE_INDEXABLE | true | false adds noindex to every page and Disallow: / to robots.txt. Use it on staging. |
INCLUDE_DRAFTS | false | true includes drafts. Only for preview builds. |
The CMS connection and previews
| Variable | Default | Meaning |
|---|---|---|
MDLAKE_API_URL | none | The read API of the workspace: https://<cms>/api/lake/<workspace>. |
MDLAKE_TOKEN | none | A workspace token. A token with the preview scope is needed for npx mdlake preview; the published scope is enough for Claude Code’s lake tools. See Workspace tokens. |
MDLAKE_MCP_URL | the origin of MDLAKE_API_URL plus /mcp | Set it only when the MCP address is different. |
MDLAKE_USAGE_REPORT | on | 0 stops the plugin’s hook from reporting AI token counts to the CMS. |
MDLAKE_PREVIEW | none | 1 or true makes the site read drafts through the API and ignore lake.lock. Set by npx mdlake preview. A production build (astro build) refuses it. |
MDLAKE_PREVIEW_POLL | 5000 | How often, in milliseconds, a preview asks the CMS for changes. |
MDLAKE_PREVIEW_DEPLOY | none | 1 allows a static build of a preview for a host that only editors can reach (the same as astro build --preview-deploy). Signed asset links in such a build expire after 15 minutes. |
MDLAKE_PLUGIN_ROOT | none | The plugin folder for check-ruleset, when it cannot find it. |
Server code: forms, mail and Turnstile
These apply to the server model and to the backend of a split site.
| Variable | Secret | Meaning |
|---|---|---|
MAIL_PROVIDER | no | resend or log. See Mail. |
RESEND_API_KEY | yes | The Resend API key. |
MAIL_FROM | no | The sender, on a domain verified in Resend. |
<RECIPIENT> (for example CONTACT_FORM_TO) | no | The recipient of one form. The name is set in src/forms/<name>.ts as recipientEnv. |
PUBLIC_TURNSTILE_SITE_KEY | no | The Turnstile site key. Read at build time and put in the page. |
TURNSTILE_SECRET_KEY | yes | The Turnstile secret key. See Turnstile. |
TRUSTED_PROXY_HOPS | no | How many proxies to trust in X-Forwarded-For, counted from the right. Default 1; the generated Bicep sets 2 for the API of a split site. |
HOST, PORT | no | Where the Node server listens. The generated App Service sets HOST=0.0.0.0. |
API_PORT | no | The local port of a separate backend and the dev proxy. Default 3001 (Node) or 5088 (.NET). |
Build and checks
| Variable | Default | Meaning |
|---|---|---|
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH | Playwright’s own Chromium | A Chromium for check-a11y, for machines where Playwright’s download is not possible. |
Files
| File | Edit it? | What it is |
|---|---|---|
astro.config.mjs | Yes | Calls defineMdlakeConfig() from @mdlake/site-kit/integration. The kit supplies static output, trailing slashes, SITE_URL, redirects.json, React, the sitemap, Tailwind and the page routes. Your Astro options win over its defaults. On the server model the kit adds the Node adapter, standalone. |
lake.config.ts | Through plan.md | Generated. defineLake({ workspace, site, documents, collections, slots }) says what the site binds to: documents by id, collections by folder and tags (with sort), slots for the site type. site is { name, cta? }: cta: { label, href } is the site’s default call to action, the brief’s primaryCta, which the end of a detail page uses when its own end.cta is not set (Site types). Hand edits need npx mdlake adopt lake.config.ts. |
lake.lock | Through the refresh flow | The locked lake commit, its remote, the time and the mode (snapshot or live). A kit file: tools write it. See Lake format. |
src/pages.config.ts | Through plan.md | Generated. The routes, their modules, the navigation (nav) and the end-of-page block (end). Headings, button labels and links are site chrome and live here. |
src/content/generated/<key>.md | Never by hand | Generated copy with provenance. |
src/forms/<name>.ts | Yes | A form definition. See Forms. |
site.config.ts | Yes | Replaces kit components. See below. |
design.md | Yes | The design: tone, colours, fonts, radius, container. apply-design.mjs writes the tokens into src/styles/global.css. |
plan.md | Yes | The brief and the plan. Generated files follow from it. |
redirects.json | Yes | A map from an old path to a new one, for slugs that changed. Edit this, not astro.config.mjs. Default {}. |
builder.json | No | The ruleset and template version the site was made from. |
provenance.json | No | The ownership record: the zone and hash of each kit and generated file, and which files are locked or adopted. |
site-snapshot.json | Through npx mdlake snapshot | The route snapshot that the refresh flow compares against. Commit it. |
.mdlake/ruleset.json | No | rulesetVersion, pluginVersion, lakeLoaderVersion, siteKitVersion, mode. |
.mdlake/hosting.json | No | The hosting model, adapter, on-demand routes and backend. Commit it. See Choose a hosting model. |
.mdlake/types/lake.d.ts | No | Typed keys, written from lake.config.ts by mdlake prepare. Gitignored. |
.mdlake/lake/ | No | The managed lake clone. Gitignored. |
CLAUDE.md | Add your own rules | The ruleset for Claude Code, written by scaffold-site and replaced by upgrade-ruleset. Keep your own rules in a separate section. |
infra/, .github/workflows/deploy.yml, azure-pipelines.yml | See below | Written by hosting init. |
api/, src/api/generated/ | api/ yes, generated no | The separate backend and its typed client. |
site.config.ts
The file is optional and site-owned. It replaces kit components; it does not change what they show.
import { defineSiteConfig } from '@mdlake/site-kit'
export default defineSiteConfig({
modules: { hero: './src/components/MyHero.astro' },
layout: './src/components/MyLayout.astro',
parts: { Prose: './src/components/MyProse.astro' },
})Unknown keys are an error. Paths are relative to the site root, or a package name. A path that does not exist is an error that lists every missing file. Restart astro dev after a change.
| Key | Accepted names |
|---|---|
modules | hero, featureGrid, steps, testimonial, stats, faq, cta, richText, caseHeader, docsPage, form, endOfPage |
parts | CardGrid, CodeCopy, DocsSearch, DocsSidebar, FormFields, LakeImage, MobileNav, Prose, SEO |
layout | A path. It can wrap the kit’s layout (@mdlake/site-kit/layouts/Layout.astro), which has the slots head, banner, header and footer. |
A replacement module gets the same props as the kit’s own: data, index and back. See Custom components.
The generated files of hosting
hosting init writes these files, each marked on its first line. Edit the parameter files freely; for anything else, adopt the file first.
| File | Zone |
|---|---|
infra/main.bicep, infra/modules/*.bicep | generated |
.github/workflows/deploy.yml, azure-pipelines.yml | generated |
infra/parameters/staging.bicepparam, production.bicepparam | yours |
package.json
Scripts, engines and dependencies of a template site:
| Item | Value |
|---|---|
engines.node | >=22.23.4 in the template’s package.json. npm warns when the Node version is lower. |
| Dependencies | astro, @astrojs/react, react, react-dom, @mdlake/site-kit, @mdlake/lake-loader |
| Dev dependencies | @astrojs/check, typescript, playwright, axe-core and the React types |
| Scripts | dev, build, preview, preview:cms, check and the check:* scripts. See CLI reference. |
The site’s own .gitignore covers node_modules/, dist/, .astro/, .env, .mdlake/lake/, .mdlake/types/, the preview and candidate files, and the usage state (.mdlake/usage-*).
What’s next
- CMS configuration for the server side.
- Lake format for the content the site reads.
- CLI reference.
