Mira
All docs

Deploying

Publish the dist folder to Vercel, Netlify, Cloudflare, GitHub Pages, Firebase, Render, Azure, Docker, Deno, or S3, with each host's config written for you.

mira build writes a complete static site to dist/. Deploying is publishing that folder. Name your hosts in mira.config.json, and Mira writes each host’s own config file on every build, so headers, clean URLs, the 404 page, redirects, and Markdown twins behave the same everywhere.

{
  "site": { "url": "https://example.com" },
  "hosts": { "vercel": {}, "netlify": {} }
}

What is in dist

PathContents
index.html, */index.htmlPages
404.htmlThe not found page
*.mdMarkdown twins
llms.txt, llms-full.txtAgent indexes
sitemap.xml, */rss.xmlWhen site.url is set
robots.txtCrawler policy
media/, media.jsonMedia frames and their manifest
_headers, _redirectsFor Netlify and Cloudflare Pages
vercel.jsonFor Vercel, when dist/ is the project root
_mira/The search index, and scripts a page uses
everything from public/As is

Before you deploy

Set site.url to your production origin so canonical URLs, the sitemap, and feeds use absolute links.

Hosts

Each key under hosts writes that host’s config. Files go in the project root unless noted. Mira only replaces files it wrote itself: if a config file you wrote by hand is in the way, the build stops and says so, and your file is left alone.

HostKeyMira writesSet up
Vercelvercelvercel.jsonImport the repository. No build command is needed.
Netlifynetlifynetlify.toml, dist/_redirectsImport the repository.
Cloudflare Pagescloudflarewrangler.toml, dist/_redirectsConnect the repository. Set hosts.cloudflare.project to the Pages project name.
GitHub Pagesgithub.github/workflows/mira-pages.ymlIn the repository settings, set Pages to deploy from GitHub Actions.
Firebase Hostingfirebasefirebase.jsonfirebase deploy --only hosting
Renderrenderrender.yamlCreate a Blueprint from the repository. hosts.render.service names the service.
Azure Static Web Appsazuredist/staticwebapp.config.jsonPoint the app at dist.
DockerdockerDockerfile, nginx.confdocker build -t site . then docker run -p 8080:8080 site
Deno Deploydenomain.tsDeploy main.ts as the entry point.
S3 and CloudFronts3cloudfront-function.jsUpload dist/ to the bucket and attach the function to the distribution’s viewer requests.

Every host gets the same behavior:

  • the security headers, with immutable caching for /fonts/ and /media/
  • URLs that end in a slash, with a permanent redirect from the version without one
  • the site’s own 404.html, with status 404
  • .md twins served as text/markdown, and, on hosts that support it, the twin for requests with Accept: text/markdown
  • every entry in redirects, as permanent redirects in the host’s own format

Vercel is verified live, Markdown negotiation included. GitHub Pages is verified too; it cannot set headers, so pages rely on their CSP meta tag there.

Redirects

When a page moves, map the old path to the new one. mira migrate fills this in for you.

{
  "redirects": {
    "/2024/05/01/hello.html": "/posts/hello/",
    "/old-docs/": "https://docs.example.com/"
  }
}

Mira writes each redirect into every host’s config. It also writes a small redirect page at the old path, with a canonical link, so hosts without redirect rules still send readers and crawlers on. A redirect cannot replace a page that exists, and the build warns when one points to a page it does not produce.

Checking a deploy

tools/check_host.py in the Mira source checks a live site. It covers status codes, URLs with and without the trailing slash, the site’s own 404 page, security headers, content types for twins and AVIF, media caching, and Markdown negotiation.

python tools/check_host.py https://your-site.example

Your own server. Serve dist/ as static files. Map a request for /path/ to /path/index.html, return 404.html with status 404 for missing files, and send .md files as text/markdown. The nginx.conf from the docker host is a complete example.

Clean URLs

Pages live at paths ending in a slash, each as an index.html in its own folder, so they work on every host without rewrite rules.

Caching

Pages carry their CSS and runtime inline, so a page is one request. Cache HTML briefly and let it revalidate. Fonts and media are marked immutable; their file names change when their contents do.