Deployment
Meno builds your entire site to static HTML files in the dist/ directory.
The output can be deployed to any static hosting provider -- Netlify,
Cloudflare Pages, GitHub Pages, Vercel, or a simple file server.
Building the Site
Run the build command from your project root:
bun run buildThe build process: - Renders every page in
pages/to static HTML. - Generates one HTML file per CMS item for every template page inpages/templates/. - Generates locale-prefixed copies of all pages if i18n is configured. - Creates auto-generated files fromproject.config.json. - Copies optional static files from the project root. - Bundles CSS and client-side JavaScript (including MenoFilter if used).
Output appears in the
dist/directory, ready to upload.
Auto-Generated Files
These files are created automatically from project.config.json settings:
File | Source | Description |
|---|---|---|
|
| Search engine directives with sitemap reference |
|
| Full sitemap including CMS item URLs and locale alternates |
Favicon tags |
|
|
Apple Touch Icon |
|
|
Configure these in project.config.json:
{
"siteUrl": "https://example.com",
"icons": {
"favicon": "/favicon.ico",
"appleTouchIcon": "/apple-touch-icon.png"
}
}Optional Static Files
If any of these files exist in your project root, they are copied to dist/
during the build:
File / Directory | Purpose |
|---|---|
| Netlify or Cloudflare Pages custom headers |
| Netlify or Cloudflare Pages redirect rules |
| GitHub Pages custom domain |
| PWA manifest |
| PWA manifest (alternative name) |
| LLM context file |
| Site credits |
| Ad network authorization |
| Security contact information |
| Well-known URI directory (entire folder copied) |
URL Redirects
Create a _redirects file in your project root. Each line defines one rule:
/old-page /new-page 301
/blog/old /blog/new 302
/app/* /index.html 200Format: source destination status-code
Status | Meaning |
|---|---|
| Permanent redirect (search engines update their index) |
| Temporary redirect |
| Rewrite (serve the destination without changing the URL) |
This file is copied as-is to the build output. The redirect behavior depends on your hosting provider (Netlify and Cloudflare Pages support this format natively).
External Libraries and CSP
If your site uses external JavaScript or CSS from CDNs, configure them in
project.config.json:
{
"libraries": {
"js": [
{ "url": "https://cdn.example.com/analytics.js" }
],
"css": [
{ "url": "https://fonts.googleapis.com/css2?family=Roboto" }
]
}
}To allow these domains through Content Security Policy headers, add them to
the csp configuration:
{
"csp": {
"scriptSrc": ["https://cdn.example.com"],
"styleSrc": ["https://fonts.googleapis.com"],
"fontSrc": ["https://fonts.gstatic.com"],
"connectSrc": ["https://api.example.com"],
"frameSrc": ["https://www.youtube.com"],
"imgSrc": ["https://images.example.com"]
}
}CSP Directive | Controls |
|---|---|
| JavaScript sources |
| CSS sources |
| Web font sources |
| Fetch/XHR/WebSocket destinations |
| Iframe embed sources |
| Image sources |
CMS Static Generation
CMS template pages are pre-rendered for every item at build time. If you have
a template at pages/templates/blog-post.json with URL pattern
/blog/{{slug}} and 50 blog items, the build produces 50 HTML files:
dist/
blog/
my-first-post.html
another-post.html
...If i18n is configured, each locale gets its own copy:
dist/
blog/
my-first-post.html
pl/
blog/
my-first-post.htmlImportant: CMS items are rendered at build time. After adding or editing items, you must rebuild and redeploy for changes to appear on the live site.
Deploying to Specific Providers
Netlify
Build the site: ``
bash bun run build``Drag and drop the
dist/folder into the Netlify dashboard, or configure a Git-based deployment with these settings: - Build command:bun run build- Publish directory:distFor custom headers or redirects, create
_headersand_redirectsfiles in your project root. They are copied todist/automatically.
Cloudflare Pages
Connect your repository to Cloudflare Pages.
Set the build command to
bun run buildand the output directory todist.Cloudflare Pages supports
_headersand_redirectsfiles natively.
GitHub Pages
Build the site and push the
dist/folder to thegh-pagesbranch, or configure GitHub Actions to build and deploy.For a custom domain, create a
CNAMEfile in your project root containing your domain name (e.g.www.example.com). It is copied todist/automatically.
Important: GitHub Pages does not support _headers or _redirects. Use
meta-refresh redirects or configure redirects at the DNS level instead.
Any Static Host
The dist/ directory contains plain HTML, CSS, and JavaScript files. Upload
them to any web server or static file host:
# Example: rsync to a server
rsync -avz dist/ user@server:/var/www/html/
# Example: AWS S3
aws s3 sync dist/ s3://my-bucket --deleteBuild Output Structure
A typical build produces:
dist/
index.html # Home page
about.html # Static page
blog/
my-post.html # CMS-generated page
another-post.html
pl/ # Locale prefix (if i18n configured)
index.html
about.html
blog/
my-post.html
assets/
style.css # Bundled CSS
meno-filter.js # Client-side filtering (if used)
data/
posts/
index.json # Client-side CMS data (if clientData enabled)
robots.txt # Auto-generated
sitemap.xml # Auto-generated
_headers # Copied from project root
_redirects # Copied from project rootFonts
Custom fonts declared in project.config.json are included in the build
with proper @font-face declarations:
{
"fonts": [
{
"path": "/fonts/Inter-VariableFont_opsz,wght.ttf",
"family": "Inter",
"weight": 400,
"fontDisplay": "swap"
}
]
}The font files must exist at the specified paths in your project. They are
copied to the build output and referenced with font-display: swap for
optimal loading performance.
Verifying the Build
Before deploying, preview the build output locally:
# Serve the dist directory with any static server
bunx serve dist
# or
npx serve distOpen http://localhost:3000 (or the port shown) and verify:
All pages render correctly.
CMS item pages are accessible at their expected URLs.
Locale-prefixed pages show the correct translations.
Client-side filtering and search work (if used).
The sitemap at
/sitemap.xmllists all pages.Font loading does not cause layout shifts.
Next Steps
CMS -- Set up collections for static generation
Lists -- Display content listings
Internationalization -- Multi-language builds
Filtering and Search -- Client-side interactivity