Deploying
Deploy a cosmo site to Cloudflare Pages, GitHub Pages, Netlify, or Vercel.
Cosmo builds to fully static HTML, CSS, and JS in ./dist/. Any static host works. Four common options are documented below.
Common build settings
Every host below uses the same build inputs:
- Install command:
pnpm install --frozen-lockfile - Build command:
pnpm build - Output directory:
dist - Node version:
22 LTS(matches.nvmrc)
Cloudflare Pages
- Push the repo to GitHub, GitLab, or Bitbucket.
- In the Cloudflare dashboard, go to Workers & Pages → Create → Pages → Connect to Git and pick the repo.
- In Build settings, set:
- Framework preset: Astro
- Build command:
pnpm build - Build output directory:
dist
- Under Environment variables (Build), add:
NODE_VERSION=22
- Save and deploy. Cloudflare will rebuild on every push to the production branch.
To use a custom domain, add it under Custom domains and point your DNS at the provided CNAME (or use Cloudflare DNS for one-click setup).
GitHub Pages
GitHub Pages serves static files from a branch or from a workflow artifact. Cosmo recommends the workflow approach — it lets the build run in CI rather than committing dist/ to the repo.
-
In the repo settings, go to Settings → Pages and set Source to GitHub Actions.
-
Add a workflow at
.github/workflows/deploy.yml:name: Deploy to GitHub Pages on: push: branches: [main] workflow_dispatch: permissions: contents: read pages: write id-token: write concurrency: group: pages cancel-in-progress: true jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build - uses: actions/upload-pages-artifact@v3 with: path: dist deploy: needs: build runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - id: deployment uses: actions/deploy-pages@v4 -
If you’re deploying to a project page (
username.github.io/repo), setbase: "/repo"inastro.config.mjsso asset paths resolve correctly. User/org pages (username.github.io) don’t need this.
Netlify
-
Push the repo to your Git provider.
-
In Netlify, go to Add new site → Import an existing project and pick the repo.
-
Set:
- Build command:
pnpm build - Publish directory:
dist
- Build command:
-
Under Site settings → Build & deploy → Environment, add:
NODE_VERSION=22NPM_FLAGS=--version(this disables Netlify’s defaultnpm installso it falls through to pnpm)
-
Optionally commit a
netlify.tomlto pin everything in the repo:[build] command = "pnpm build" publish = "dist" [build.environment] NODE_VERSION = "22"
Netlify auto-detects pnpm via pnpm-lock.yaml and installs it for you.
Vercel
- Push the repo to your Git provider.
- In Vercel, click Add New → Project, import the repo, and accept the auto-detected Astro preset.
- Vercel reads
pnpm-lock.yamland uses pnpm automatically. Defaults work:- Build command:
pnpm build - Output directory:
dist - Install command:
pnpm install
- Build command:
- Under Project Settings → General, confirm Node.js Version is
22.x. - Deploy. Every push to the production branch redeploys; PRs get preview URLs automatically.
After your first deploy
- Verify the sitemap is reachable at
/sitemap-index.xmland thatrobots.txtpoints to the production URL. - Test the RSS feed at
/rss.xml. - Check that OG images render by pasting your URL into the Open Graph debugger or a Slack/Discord message.
- Run PageSpeed Insights against the deployed URL to confirm the build is performing as expected.