Deploy
pnpm build writes a static site to dist/. There is no server, no adapter and no
runtime: any static host will serve it.
Two things to do before the first deploy.
-
Set
site.urlinsrc/config.tsto the address the site will actually have. Canonical links, the sitemap, the feeds and the share cards are absolute, and they are all wrong until you do.SITE_URLin the build environment overrides it, which is useful for preview deployments:SITE_URL=https://staging.example.com pnpm build -
Run the gate:
pnpm check && pnpm build. A build that fails on a host usually fails locally first.
Your own repository
The Pro repository is private and cannot be forked. Start your site as a repository of your own:
git clone https://github.com/ondelva/astro-theme-leader-pro.git my-workshop
cd my-workshop
rm -rf .git
git init && git add -A && git commit -m "Leader Pro"
git remote add origin [email protected]:you/my-workshop.git
git push -u origin main
From the zip, unpack it and start at git init.
Taking an update. Releases within 1.x are yours for the life of the licence. Keep the theme as a second remote and merge the release tag:
git remote add theme https://github.com/ondelva/astro-theme-leader-pro.git
git fetch theme --tags
git merge v1.1.0 --allow-unrelated-histories # first time only
Your content lives in src/content/ and your changes in src/config.ts and
src/styles/theme.css, so the conflicts are usually few and always in files you have
edited. Read CHANGELOG.md first.
Cloudflare Pages
Create a project, connect the repository, and set:
- Framework preset: Astro
- Build command:
pnpm build - Output directory:
dist - Environment variable:
NODE_VERSION=22
Cloudflare reads packageManager in package.json and uses the right pnpm.
Vercel
Import the repository; Vercel detects Astro and fills in pnpm build and dist. Nothing
else is needed. Set SITE_URL as an environment variable if you want preview deployments
to have correct canonical URLs.
Netlify
Import the repository and set:
- Build command:
pnpm build - Publish directory:
dist - Environment variable:
NODE_VERSION=22
Anywhere else
Upload dist/. It is plain files. A 404.html is generated, so point the host’s not-found
handler at it if that is not automatic.
Continuous integration
.github/workflows/ci.yml runs on push and pull request: pnpm check, pnpm lint,
pnpm check:contrast, pnpm build, Lighthouse CI against the thresholds in
lighthouserc.cjs, and an internal link check over dist/. It needs no secrets. Delete the
file if you would rather not run it.
The integrations, once you are live
Each of these is off until you fill in src/config.ts, and each is a plain form post or a
single script — nothing is loaded while the settings are empty.
| What | What to fill in |
|---|---|
| Analytics | analytics.provider and analytics.id. host only for self-hosted Plausible or Umami |
| Contact form | contact.endpoint from Formspree, Web3Forms or Basin. Web3Forms also wants contact.accessKey, and contact.redirect if you would rather land on your own page than the provider’s |
| Newsletter | newsletter.provider: 'buttondown' and newsletter.id (your buttondown.com username), then the two return addresses in Buttondown — step by step in customization.md |
| Comments | features.comments: true plus the four ids from giscus.app, after installing the giscus app on a repository with Discussions enabled |
Submit the contact form and the newsletter form once on the deployed site. Both post to somebody else’s server, and the only way to know the key is right is to watch a message arrive.
After deploying
- Search is indexed at build time, so check it on the deployed site — or on
pnpm preview— rather than inpnpm dev. - Share cards are generated per product and note when
seo.ogImagesis on. Paste a couple of URLs into a card validator once; after that they take care of themselves. /robots.txtis generated fromsite.urland points at the sitemap. It allows everything; editsrc/pages/robots.txt.tsto narrow it.- The legal pages (
src/pages/privacy.astro,terms.astro) are placeholders. Replace them.
Next: Content