Official documentation site for Maildeno — the visual email template builder with a powerful render API.
Built with Antora and deployed to Cloudflare Pages.
- Project structure
- Local development
- Writing documentation
- Adding images
- Deployment
- Environment setup (CI/CD)
- Custom domain
- Troubleshooting
maildeno-docs/
├── antora-playbook.yml # Production build (pulls from GitHub)
├── antora-playbook-local.yml # Local development build (reads from disk)
├── wrangler.toml # Cloudflare Pages project config
├── package.json
│
├── .github/
│ └── workflows/
│ └── deploy.yml # CI/CD: build + deploy on push to main
│
├── docs/
│ ├── antora.yml # Component descriptor (name, version, nav)
│ └── modules/
│ ├── ROOT/ # Top-level pages (index, quickstart, concepts)
│ │ ├── nav.adoc
│ │ ├── pages/
│ │ └── images/ # ← Put ROOT-level screenshots here
│ │
│ ├── builder/ # Email builder documentation
│ │ ├── nav.adoc
│ │ ├── pages/
│ │ └── images/ # ← Put builder screenshots here
│ │
│ └── sdk/ # SDK reference documentation
│ ├── nav.adoc
│ └── pages/
│
└── ui/
└── supplemental-ui/
├── _redirects # Cloudflare Pages URL redirects
└── _headers # HTTP security headers
| Tool | Version |
|---|---|
| Node.js | ≥ 18 |
| npm | ≥ 9 |
git clone https://github.com/maildeno/docs.git
cd docs
npm install# One command: build the site then open it at http://localhost:5000
npm run devThis runs two steps:
npm run build:local— Antora reads content from your local filesystem (no network fetch from GitHub).npm run serve— starts a local HTTP server athttp://localhost:5000and opens your browser.
npm run build:local
# Output: build/site/Antora doesn't have built-in watch mode. For faster iteration:
# Terminal 1 — keep the server running
npx http-server build/site -p 5000 -c-1
# Terminal 2 — rebuild after editing a page
npm run build:local
# Refresh your browser to see changesTip: Use a browser extension like LiveReload or run browser-sync in proxy mode for automatic refreshes.
npm run cleanDocumentation is written in AsciiDoc. Pages live under docs/modules/<module>/pages/.
| Module | Path | Purpose |
|---|---|---|
ROOT |
docs/modules/ROOT/ |
Top-level pages — home, quickstart, concepts |
builder |
docs/modules/builder/ |
Email builder feature docs |
sdk |
docs/modules/sdk/ |
SDK and REST API reference |
- Create a
.adocfile under the appropriatepages/directory. - Add a title and description:
= Page Title
:description: One-sentence description for SEO.
Content starts here.- Add it to the module's
nav.adoc:
* xref:my-new-page.adoc[My New Page]// Same module
xref:other-page.adoc[Link text]
// Different module
xref:builder:merge-tags.adoc[Merge Tags]
xref:sdk:javascript.adoc[JavaScript SDK][source,typescript]
----
const html = await client.renderHtml("template-id")
----NOTE: A tip or additional context.
TIP: A helpful hint.
WARNING: Something the user should be careful about.
CAUTION: A potentially destructive or irreversible action.
IMPORTANT: A critical piece of information.[tabs]
====
JavaScript::
+
[source,typescript]
----
const html = await client.renderHtml("id")
----
Python::
+
[source,python]
----
html = client.render_html("id")
----
====Place images in the images/ directory of the relevant module:
docs/modules/ROOT/images/ ← for ROOT pages
docs/modules/builder/images/ ← for builder pages
docs/modules/sdk/images/ ← for SDK pages
Reference them in .adoc files:
// Image in the same module
image::my-screenshot.png[Alt text description,role=center,width=100%]
// Image from another module
image::builder:editor-canvas.png[Editor canvas,role=center,width=100%]Image naming convention:
<module>-<feature>-<description>.png
Examples:
canvas.png
email-health.png
merge-tag-detected.png
vis-rule.png
Push to main to trigger a production deployment:
git add .
git commit -m "docs: update SDK error handling guide"
git push origin mainThe GitHub Actions workflow will:
- Install dependencies and build with Antora.
- Deploy the
build/site/output to Cloudflare Pages. - Post the deployment URL to the Actions run summary.
Open a pull request against main. The workflow deploys to a unique preview URL and posts it as a PR comment.
Install Wrangler and authenticate:
npm install -g wrangler
wrangler loginBuild and deploy:
npm run build:local
wrangler pages deploy build/site --project-name=maildeno-docsAdd these to GitHub → Settings → Secrets and variables → Actions:
| Secret | Where to find it |
|---|---|
CLOUDFLARE_API_TOKEN |
Cloudflare Dashboard → My Profile → API Tokens → Create Token → use the Edit Cloudflare Workers template, then add Cloudflare Pages:Edit permission. |
CLOUDFLARE_ACCOUNT_ID |
Cloudflare Dashboard → right-hand sidebar on the home page. |
| Variable | Default | Description |
|---|---|---|
CF_PAGES_PROJECT_NAME |
maildeno-docs |
Cloudflare Pages project name. |
GA_MEASUREMENT_ID |
(empty) | Google Analytics 4 Measurement ID (e.g. G-XXXXXXXXXX). |
Before the first deploy, create the Pages project:
wrangler pages project create maildeno-docs --production-branch=mainOr create it in the Cloudflare dashboard under Workers & Pages → Create application → Pages.
- In the Cloudflare dashboard, go to Workers & Pages → maildeno-docs → Custom domains.
- Add
docs.maildeno.com. - Follow the DNS instructions (add a CNAME pointing to your Pages deployment).
Uncomment and update the routes block in wrangler.toml:
[env.production]
routes = [
{ pattern = "docs.maildeno.com", custom_domain = true }
]You are running npm run build (production playbook) locally. This playbook fetches content from GitHub. Use npm run build:local for local development.
The HTTP server serves cached files. Hard-refresh your browser (Ctrl+Shift+R / Cmd+Shift+R) or restart the server.
Check that:
- The target page exists at the path used in the
xref:. - The module name in the
xref:matches the directory name underdocs/modules/. - The nav file for the module is listed in
docs/antora.yml.
The CLOUDFLARE_API_TOKEN secret is missing, expired, or lacks the Cloudflare Pages:Edit permission. Rotate it in the Cloudflare dashboard and update the GitHub secret.
Confirm the image file exists in docs/modules/<module>/images/ and is committed to git. Image references are case-sensitive.
MIT