Deploy
Build output
Every template generates a static site:
npm run build # → dist/
The dist/ folder contains plain HTML, CSS, JS and images — upload it to any static host.
Before you deploy
Update the site URL in astro.config.mjs:
export default defineConfig({
site: "https://www.yourdomain.com",
// ...
});
This sets canonical URLs, OG image paths and the sitemap base.
Cloudflare Pages
- Push your repo to GitHub or GitLab
- Cloudflare dashboard → Pages → Create project → Connect repository
- Build settings:
- Build command:
npm run build - Build output directory:
dist - Node version: auto-detected from
.node-version(22)
- Build command:
- Add your custom domain in Pages → Custom domains
Every push triggers a new deploy automatically.
Netlify
- Push your repo to GitHub or GitLab
- Netlify → Add new site → Import from Git
- Build settings are pre-configured in
netlify.toml(included in every template):[build] command = "npm run build" publish = "dist" - Add your custom domain in Site settings → Domain management
Vercel
- Push your repo to GitHub or GitLab
- Vercel → New project → Import repository
- Framework preset: Astro (auto-detected)
- Build command:
npm run build, output:dist - Set Node version to 22 in Settings → General
Any other host
npm run build
# Upload the contents of dist/ to your host
Templates are host-agnostic: the .node-version file and netlify.toml ship with every template for convenience, but work on any platform that serves static files.
Forms on different hosts
The reservation/contact form works differently depending on your host:
| Host | Setup |
|---|---|
| Formspree / Basin | Paste your endpoint URL into formAction in site.ts — works everywhere |
| Netlify | Forms work automatically via data-netlify="true" (already in markup) |
| Cloudflare / Vercel | Use Formspree, Basin or any form API — set the endpoint in site.ts |