Skip to content
AstroCraft Docs
On this theme

Deployment

pnpm build writes 109 HTML files and their assets to dist/. There is no adapter, no server output, no runtime — every route is prerendered, including the four generated endpoints. Any static host serves it: Netlify, Vercel, Cloudflare Pages, GitHub Pages, S3, nginx.

pnpm build     # -> dist/
pnpm preview   # serve dist/ locally exactly as a host would

Two settings shape what lands there. trailingSlash: "always" makes the build emit directory-style URLs (/used-cars/index.html), and canonical, og:url and every internal href agree on that shape — one canonical form, no redirect chain. And vite.build.assetsInlineLimit: 0 stops short scripts being inlined, because inlined scripts break under <ClientRouter /> view transitions. Leave it at zero; the comment in astro.config.mjs says so for the next person.

The production gate

Set SITE_URL in your host’s build environment before the first production deploy. If you forget, the build fails with the reason named:

SITE_URL is unset or still the placeholder. Set it to your production domain
in your host's environment variables before deploying.

The gate reads each host’s own production signal — CONTEXT=production on Netlify, VERCEL_ENV=production on Vercel, or DEPLOY_ENV=production anywhere else. None of those is set by a local pnpm build or a deploy preview, so previews and local work build freely on the placeholder. On a host not in that list, set DEPLOY_ENV yourself; the check is only as good as the signal it can see.

It is worth understanding why this is a hard failure rather than a warning. site feeds canonical, OG, JSON-LD, the sitemap, robots.txt and llms.txt. All six are invisible in review — a page with a canonical pointing at example.com renders perfectly — and by the time a crawler tells you, it has already indexed the wrong domain.

Before you deploy

  1. SITE_URL in the host’s build environment.
  2. public/og.jpg — replace the placeholder with a real 1200×630 social image. It is also the JSON-LD logo until you swap that for a brand mark; BaseHead says so in a ponytail: note.
  3. src/config/siteData.json.ts — name, author, and the sameAs list.
  4. src/config/legalData.json.ts — the terms and privacy copy are placeholders. Have them reviewed.
  5. Favicons — public/favicon.svg and public/favicon.ico.
  6. The editorial figures in navData and the browse headers, if you are wiring a real index feed.
  7. Delete the dev catalog, once you have stopped shopping for primitives.

The dev catalog’s cost

src/components/Sections/UiCatalog/ and src/pages/examples/ emit no pages in a production build — getStaticPaths returns [] under import.meta.env.PROD. But Tailwind scans source, not output, so every demo class in the catalog is compiled into the stylesheet that every page loads.

Measured on this build: deleting both directories takes the shared BaseLayout stylesheet from 113,715 to 95,172 bytes — 18,543 bytes, about 16% — and drops the built @keyframes count from 92 to 23, because the catalog is the only thing referencing most of the motion library.

That is CSS, not JavaScript, and it is per-page on first load only. Keep the catalog while you are still picking primitives; it is the fastest way to see all 37. Delete it before launch.

What a host needs

Nothing beyond static file serving. If your host lets you choose, keep directory-style URLs (/used-cars/ serving /used-cars/index.html) so they match trailingSlash: "always"; most do this by default. The only file worth a cache rule is /rss.xml, and only if you publish often.

Three routes ship noindex in their markup and are excluded from the sitemap by the filter in astro.config.mjs: /sign-in/, /saved/ and the 404. They are static demos of account screens, so they are built but deliberately not indexable — SEO explains the reasoning.

NEXT STEPContent Collections