Skip to content

Quick Deploy

Ready to make the template your own and deploy to production? This guide walks you through personalization, deployment, and verification in under an hour.

Prerequisites: You should have completed the Launch Demo and have the site running locally.

Before starting this guide, ensure you have:

  • Completed Launch Demo successfully
  • Site runs locally without errors (pnpm run dev)
  • No console errors in browser (F12 → Console)
  • pnpm run build succeeds locally (requires SITE_URL — see Step 1.1)
  • Git basics understood (commit, push, remote)
  • Hosting platform account created (or will create during guide)

Why this matters: Deploying a broken local site wastes time. Fix issues locally first.

Test your local build:

Terminal window
pnpm run preview:build # Builds and serves the production build locally

Open http://localhost:4321 - if this works, you’re ready to deploy.

Time Required: 45-75 minutes (first-time users)

Section titled “Time Required: 45-75 minutes (first-time users)”
  • Site personalized with your branding
  • Deployed to production
  • Live at your custom URL
  • Verified and tested
  • Completed Launch Demo - Local site running successfully
  • GitHub account (sign up)
  • Hosting platform account (see Platform Selection below)
  • Basic Git knowledge (commit, push)

Choose your hosting platform before starting:

PlatformBest ForFree TierSetup TimeAuto HTTPSRecommendation
GitHub Pages ⭐Zero setup — the template ships the workflowPublic repos5 min✅Ships preconfigured (see Option E)
Cloudflare PagesPerformance, global CDNUnlimited sites10-15 min✅ InstantBest managed host for most
VercelNext.js ecosystem, teams100GB/month10-15 min✅ InstantGreat for existing Vercel users
NetlifyForms, split testing, CMS100GB/month10-15 min✅ InstantGood for marketing sites

When you run pnpm run build, here’s what happens:

  1. Environment Validation (env:validate)

    • Checks that SITE_URL (or PUBLIC_SITE_URL) is set to a real URL
    • Fails the build if the variable is missing or still a placeholder (example.com, your-username, your-domain, localhost)
  2. Token Compilation (tokens:build)

    • Reads tokens/base.json and tokens/semantic.json
    • Generates CSS custom properties
    • Outputs to tokens/dist/tokens.css and tokens/dist/tailwind-tokens.json (git-ignored, regenerated on every build)
  3. Astro Build (astro build)

    • Compiles .astro components to HTML
    • Bundles JavaScript (only interactive islands)
    • Optimizes CSS (removes unused styles)
    • Processes images (AVIF + WebP)
    • Generates sitemap
  4. Output (dist/)

    • Static HTML files
    • Optimized assets (CSS, JS, images)
    • Public files (favicon, fonts, etc.)

The dist/ folder is what gets deployed - not your source code.

Copy this into your notes and check off as you go:

- [ ] Prerequisites verified
- [ ] Platform account created
- [ ] Repository created on GitHub
- [ ] Site configuration updated
- [ ] Metadata personalized
- [ ] Favicons replaced
- [ ] Design tokens customized (optional)
- [ ] Changes committed to Git
- [ ] Pushed to GitHub
- [ ] Connected to hosting platform
- [ ] Build successful
- [ ] Live site verified
- [ ] Mobile tested

🎨 Step 1: Personalize Your Site (20-30 min)

Section titled “🎨 Step 1: Personalize Your Site (20-30 min)”

File: .env (project root — copy from .env.example)
Why: astro.config.mjs derives site from the SITE_URL (or PUBLIC_SITE_URL) environment variable, which drives SEO, sitemaps, and asset linking. There is no hardcoded URL to edit — and the build fails at the env:validate step if the variable is unset or still a placeholder (example.com, your-username, your-domain, localhost).

Terminal window
# .env (copied from .env.example — dev-only default)
PUBLIC_SITE_URL=http://localhost:4321
.env
SITE_URL=https://your-actual-domain.com
# OR the origin your host gives you, e.g.
# SITE_URL=https://<github-username>.github.io (shipped GitHub Pages workflow)
# SITE_URL=https://my-project.pages.dev (Cloudflare Pages)
  1. Copy .env.example to .env if you haven’t already (cp .env.example .env)
  2. Set SITE_URL to your domain or your expected *.pages.dev URL
  3. Save the file — astro.config.mjs reads the variable at build time; don’t edit the config itself
  4. In Step 2.2 you’ll add the same SITE_URL as an environment variable on your hosting platform (.env is git-ignored, so the platform can’t see it). The shipped GitHub Pages workflow is the exception: it resolves SITE_URL itself (see Option E)

File: src/config.ts
Why: Controls the site title, description, author, and links used in meta tags and social sharing
Lines: ~10-40 (siteMetadata and siteLinks)

Open src/config.ts and update these values (the layout’s <Head /> component reads them, so you don’t need to edit src/layouts/BaseLayout.astro directly):

  • siteMetadata.title → 'Your Site Name' (appended to page titles as Page Title | Your Site Name, and used for Open Graph/Twitter tags)
  • siteMetadata.description → fallback description for pages that don’t provide their own
  • siteMetadata.author → your name (used in meta tags and structured data)
  • siteLinks.github → your repository URL (used in header, footer, and CTA links)
Show full diff with before/after
src/config.ts
export const siteMetadata = {
title: "Astro Performance Starter",
title: "Your Site Name",
description: "A production-ready Astro starter focused on performance, accessibility, and DX.",
description: "Your site description for SEO",
author: "Your Name",
author: "Jane Developer",
} as const;
export const siteLinks = {
github: "https://github.com/clownware/astro-performance-starter",
github: "https://github.com/YOUR_USERNAME/YOUR_REPO",
// ...
} as const;

Files: public/favicon.svg (and variants)
Why: Your site icon in browser tabs and bookmarks

Specifications:

  • SVG: Recommended, scalable, supports dark mode
  • PNG: Fallback, 32×32px minimum, 512×512px ideal
  • ICO: Legacy support, 16×16 and 32×32 sizes
  1. Create your favicon (use Favicon.io or design tool)
  2. Replace public/favicon.svg with your SVG
  3. (Optional) Add public/favicon.ico for legacy browsers
  4. (Optional) Add public/favicon-32x32.png and public/favicon-16x16.png

Verify:

Terminal window
# Check files exist
ls -la public/favicon*
# Should show:
# favicon.svg (required)
# favicon.ico (optional)
# favicon-32x32.png (optional)

Files:

  • tokens/semantic.json - Brand colors
  • src/components/structural/Header.astro - Logo text

Quick Color Change:

Brand colors live in the role-based semantic.primary and semantic.secondary scales (ADR-047). Each step (50-950) aliases a color ramp defined in tokens/base.json — by default color.violet for primary and color.rose for secondary:

// tokens/semantic.json (excerpt — the real file has the full 50-950 scale)
{
"semantic": {
"primary": {
"500": { "value": "{color.violet.500}" }
},
"secondary": {
"500": { "value": "{color.rose.500}" }
}
}
}

To change brand colors, either repoint the primary/secondary steps at a different base ramp (e.g. {color.amber.500}), or edit the ramp’s HSL channel values in tokens/base.json (e.g. "500": { "value": "256 86% 63%" }).

Rebuild tokens:

Terminal window
pnpm run tokens:build # Compile tokens only
# Or rebuild everything:
pnpm run build

Update the logo:

Replace public/logo.svg with your own logo file. The header (src/components/structural/Header.astro) renders it as an image — update its alt text to your brand name while you’re there.

Before deploying, verify everything looks correct:

Terminal window
# Restart dev server
pnpm run dev
# Open http://localhost:4321

Verification checklist:

  • New title appears in browser tab
  • New favicon displays
  • Updated metadata (view page source: Ctrl/Cmd+U)
  • Logo text updated (if changed)
  • Colors updated (if changed)
  • No console errors (F12 → Console)

🚀 Step 2: Deploy to Production (15-20 min)

Section titled “🚀 Step 2: Deploy to Production (15-20 min)”

Check your Git status first:

Terminal window
# Check if Git is already initialized
git status
# If you see "not a git repository", initialize it:
git init
Terminal window
git add .
git commit -m "feat: personalize site configuration and branding"
git push
Terminal window
# Stage all changes
git add .
# Commit with message
git commit -m "feat: personalize site configuration and branding"

Create GitHub repository:

  1. Go to github.com/new
  2. Name your repository (e.g., my-astro-site)
  3. Choose Public or Private
  4. Do NOT initialize with README (you already have files)
  5. Click Create repository

Connect and push:

Terminal window
# Add remote (replace with your GitHub username and repo name)
git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git
# Rename branch to master (the template's default branch, if needed)
git branch -M master
# Push to GitHub
git push -u origin master
  1. Go to dash.cloudflare.com/sign-up
  2. Enter email and create password
  3. Verify email address
  1. In Cloudflare dashboard, navigate to Workers & Pages
  2. Click Create Application
  3. Select Pages tab
  4. Click Connect to Git
  5. Choose GitHub and authorize Cloudflare
  6. Select your repository from the list
Project name: your-project-name
Production branch: master
Build command: pnpm run build
Build output directory: dist
Root directory: (leave empty)
Environment variables: SITE_URL=https://your-project-name.pages.dev (REQUIRED)
  1. Click Save and Deploy
  2. Wait 2-5 minutes for build to complete
  3. Your site will be live at https://your-project-name.pages.dev

Your site is now live, but it may be using the guessed URL from Step 1.1. Let’s fix that:

  1. Copy your actual URL from Cloudflare (e.g., https://my-project-abc.pages.dev)

  2. Update the platform variable: in your Pages project, go to Settings → Environment Variables and set SITE_URL to the actual URL

  3. Update your local .env to match, so local production builds agree with the platform

  4. Trigger a rebuild — changing an environment variable doesn’t redeploy by itself: use Deployments → Retry deployment, or push any commit

  5. Verify the new build succeeded in Cloudflare dashboard

When and How to Use Environment Variables

When you need environment variables:

  • API keys for third-party services
  • Analytics tracking IDs
  • CMS endpoints
  • Feature flags

Type-Safe Environment Variables with astro:env:

The template already configures astro:env (the top-level env option in astro.config.mjs, see ADR-050) with a schema for its PUBLIC_* variables. Note that SITE_URL, PUBLIC_SITE_URL, and DEPLOY_TARGET are intentionally not in that schema — they’re read at config-load time (before astro:env exists) and validated by the env:validate prebuild script instead. Don’t add them to the schema or re-derive site yourself.

1. Add new variables to the existing schema in astro.config.mjs:

// astro.config.mjs — extend the existing env.schema block
env: {
schema: {
// ...existing PUBLIC_* fields...
API_KEY: envField.string({
context: 'server',
access: 'secret',
}),
},
},

2. Add to your hosting platform:

Cloudflare Pages:

  • Go to Settings → Environment Variables
  • Add SITE_URL, API_KEY, etc.
  • Separate variables for Production and Preview environments

Vercel:

  • Go to Settings → Environment Variables
  • Add variables with environment selection (Production, Preview, Development)

Netlify:

  • Go to Site settings → Environment variables
  • Add variables (applies to all deploys by default)

3. Use in your code:

---
import { API_KEY } from 'astro:env/server';
const response = await fetch('https://api.example.com/endpoint', {
headers: { Authorization: `Bearer ${API_KEY}` },
});
---

Security best practices:

  • Never commit .env files to Git (already in .gitignore)
  • Use access: 'secret' for sensitive data (API keys, tokens)
  • Use access: 'public' for non-sensitive config (site URL, feature flags)

See Vercel Deployment Guide for detailed instructions.

Quick steps:

  1. Go to vercel.com/new
  2. Import your GitHub repository
  3. Build command: pnpm run build
  4. Output directory: dist
  5. Deploy

See Netlify Deployment Guide for detailed instructions.

Quick steps:

  1. Go to app.netlify.com/start
  2. Connect to GitHub
  3. Build command: pnpm run build
  4. Publish directory: dist
  5. Deploy
More Platform Options

Best for: Full-stack apps, databases, background workers

  1. Go to render.com
  2. Click New → Static Site
  3. Connect GitHub repository
  4. Build command: pnpm run build
  5. Publish directory: dist
  6. Deploy

Pros: Free SSL, global CDN, preview environments

Option E: GitHub Pages (ships preconfigured)

Section titled “Option E: GitHub Pages (ships preconfigured)”

Best for: The zero-setup path — open source projects, portfolios, documentation sites

The template already ships this workflow — .github/workflows/deploy.yml (“Deploy to GitHub Pages”) runs on every push to master (and on manual workflow_dispatch), builds with pnpm run build, and publishes dist/ through actions/deploy-pages. Do not write your own. Its “Resolve SITE_URL” step is what makes the build pass env:validate without any .env on the runner:

# .github/workflows/deploy.yml (already in the template — excerpt)
- name: Resolve SITE_URL
shell: bash
run: |
if [ -n "${SITE_URL_OVERRIDE}" ]; then
echo "SITE_URL=${SITE_URL_OVERRIDE}" >> "$GITHUB_ENV"
echo "Using custom SITE_URL=${SITE_URL_OVERRIDE} (base path /)"
else
echo "SITE_URL=https://${{ github.repository_owner }}.github.io" >> "$GITHUB_ENV"
echo "DEPLOY_TARGET=gh-pages" >> "$GITHUB_ENV"
echo "Using default project-Pages SITE_URL (base path /${{ github.event.repository.name }})"
fi
env:
SITE_URL_OVERRIDE: ${{ vars.SITE_URL }}
- name: Build site
run: pnpm run build
  1. Enable GitHub Pages:

    • Repo → Settings → Pages
    • Source: GitHub Actions
  2. Push to master — the workflow builds and deploys; your site appears at https://<github-username>.github.io/<repo-name>/.

  3. Base path is automatic: with DEPLOY_TARGET=gh-pages, astro.config.mjs derives the /<repo-name> base path from the name field in package.json — do not hand-add base (or site) to the config. If you rename the repo, update package.json’s name to match.

  4. Custom domain (optional): add the CNAME at your DNS provider, set the domain under Settings → Pages → Custom domain (enable Enforce HTTPS), then create a repository variable SITE_URL=https://your-domain.example (Settings → Secrets and variables → Actions → Variables tab — a variable, not a secret). The workflow reads vars.SITE_URL, skips DEPLOY_TARGET, so the base path becomes / (a custom domain serves the project site from the root), and bakes the new origin into canonical/OG URLs and the sitemap. Delete the variable to return to the default <github-username>.github.io/<repo-name> origin. No workflow edit is needed either way.

  1. In your Pages project, go to Custom domains
  2. Click Set up a custom domain
  3. Enter your domain (e.g., yourdomain.com)
  4. Follow DNS configuration instructions:
    • Add CNAME record pointing to your-project.pages.dev
    • Or use Cloudflare nameservers (recommended)
  5. Wait for DNS propagation (5-30 minutes)

Update the SITE_URL variable:

  1. In your Pages project, go to Settings → Environment Variables and set SITE_URL to https://yourdomain.com
  2. Update your local .env to match
  3. Trigger a rebuild (Deployments → Retry deployment, or push any commit)

Custom domains on the shipped workflow are driven entirely by the SITE_URL repository variable — see Option E, step 4. Set the domain under Settings → Pages, add the SITE_URL variable, and re-run the workflow (push a commit or use Run workflow on the Actions tab). Update your local .env to the same origin so local production builds agree with CI.

2.5 CI/CD Integration (Optional, Advanced)

Section titled “2.5 CI/CD Integration (Optional, Advanced)”
Custom Deployment Pipelines with GitHub Actions

You already have one. .github/workflows/deploy.yml is the template’s GitHub Pages pipeline (Option E). It is the deployment the template supports out of the box — keep it, even if you deploy elsewhere: it costs nothing while GitHub Pages is disabled for the repo, and it stays the reference for how SITE_URL and DEPLOY_TARGET are resolved in CI.

Why add a second Actions workflow instead of a platform’s native Git integration?

Managed hosts (Cloudflare Pages, Vercel, Netlify) deploy automatically when you push. GitHub Actions gives you more control for advanced use cases:

  • Run tests before deployment - Prevent broken builds from going live
  • Custom build steps - Complex preprocessing, code generation
  • Multi-environment deploys - Staging, preview, production from one workflow
  • Service integrations - Slack notifications, cache invalidation
  • Monorepo deployments - Deploy multiple projects from one repo

If you just need “push to deploy,” stick with the shipped workflow or the platform’s native Git integration. A second workflow adds complexity.

Optional alternative: deploy to Cloudflare Pages from Actions

Section titled “Optional alternative: deploy to Cloudflare Pages from Actions”

Add this as a new file — do not overwrite the shipped deploy.yml:

# .github/workflows/deploy-cloudflare.yml (new file — leaves deploy.yml untouched)
name: Deploy to Cloudflare Pages
on:
push:
branches: [master]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
- name: Setup PNPM
uses: pnpm/action-setup@v6
with:
run_install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build site
run: pnpm run build
env:
SITE_URL: ${{ vars.SITE_URL }}
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist --project-name=your-project-name

Notes on that file:

  • pnpm/action-setup reads the pinned version from the packageManager field in package.json, the same way the shipped deploy.yml does — no version: input needed.
  • SITE_URL must reach the build or env:validate fails it. Here it comes from a repository variable (Settings → Secrets and variables → Actions → Variables); leave DEPLOY_TARGET unset so the site builds for the root path.
  • Disable the Cloudflare project’s own Git integration once this workflow is in place, or you’ll deploy twice per push.
  1. Add secrets to GitHub:

    • Go to your repo → Settings → Secrets and variables → Actions
    • Add CLOUDFLARE_API_TOKEN (get from Cloudflare dashboard)
    • Add CLOUDFLARE_ACCOUNT_ID (found in Cloudflare URL)
  2. Get Cloudflare credentials:

    • API Token: Cloudflare dashboard → My Profile → API Tokens → Create Token
    • Use “Edit Cloudflare Workers” template
    • Account ID: In Cloudflare Pages project URL

Vercel automatically deploys on push without additional configuration. Just connect your repo and set SITE_URL in the project’s environment variables.

Netlify also auto-deploys on push. Configure in netlify.toml (versions match the template’s .nvmrc and packageManager pins):

[build]
command = "pnpm run build"
publish = "dist"
[build.environment]
NODE_VERSION = "24.21.0"
PNPM_VERSION = "11.27.1"

✓ Step 3: Verify Your Deployment (5-10 min)

Section titled “✓ Step 3: Verify Your Deployment (5-10 min)”

Visit your live site and verify:

  • Site loads without errors
  • Correct title in browser tab
  • Correct favicon displays
  • Homepage displays correctly
  • Showcase page works (/showcase/)
  • Dark mode toggle works
  • Mobile responsive (test on phone or DevTools)
  • No console errors (F12 → Console)
  • No 404 errors for assets

Run a Lighthouse audit to verify performance:

  1. Open your live site
  2. Press F12 → Lighthouse tab
  3. Click Analyze page load
  4. Check scores
  1. Go to pagespeed.web.dev
  2. Enter your live URL
  3. Click Analyze

WCAG AA Compliance Check:

  1. WAVE Browser Extension

  2. Axe DevTools

    • Install: Chrome Web Store
    • Open DevTools (F12) → Axe DevTools tab
    • Click Scan ALL of my page
    • Fix any critical or serious issues
  3. Lighthouse Accessibility Audit

    • Already included in Lighthouse (see Option 1)
    • Target: 95+ (the CI floor is 0.95)

Common accessibility checks:

  • All images have alt text
  • Heading hierarchy is logical (h1 → h2 → h3)
  • Color contrast meets WCAG AA (4.5:1 for text)
  • Keyboard navigation works (Tab, Enter, Escape)
  • Focus indicators are visible
  • Form inputs have labels
  • ARIA attributes used correctly

These scores assume:

  • No additional content yet
  • No third-party scripts (analytics, ads)
  • Only the template’s two self-hosted fonts (Geist for display, Inter for body — vendored WOFF2 served through the Astro Fonts API, ADR-053)
  • No large images

The template’s headline claim is 95+ in every category, and CI (.github/workflows/lighthouse.yml, using lighthouserc.json for desktop and lighthouserc.mobile.json for mobile) fails the build when a category drops below its floor:

MetricTargetCI floorWhy This Score
Performance95+0.90Astro’s static output is blazing fast
Accessibility95+0.95Semantic HTML + ARIA best practices
Best Practices95+0.95HTTPS, modern standards, no deprecated APIs
SEO95+0.90Meta tags, sitemap, semantic structure

As you add content, scores will change. This is normal. Focus on:

  • Image optimization (use Astro’s <Image /> component)
  • Lazy loading for non-critical content
  • Keeping third-party scripts minimal

Common score impacts:

  • Performance drops to 85-90 - After adding 10+ images, custom fonts, or analytics
  • Accessibility drops to 95-98 - Missing alt text on new images, contrast issues in custom designs
  • Best Practices drops to 95 - Third-party scripts (Google Analytics, ad networks)
  • SEO stays 100 - Unless you forget meta descriptions or have broken internal links

Goal: Stay above the CI floors as you add content (Performance and SEO ≥ 90, Accessibility and Best Practices ≥ 95) — lighthouse.yml fails the check otherwise.

Quick Wins:

  1. Chrome DevTools Device Mode (Ctrl/Cmd+Shift+M)

    • Test iPhone 14 Pro, Pixel 7, iPad Pro
    • Toggle device toolbar, rotate orientation
    • Good enough for most cases
  2. Free Real Device Testing

    • LambdaTest - 100 minutes/month free
    • BrowserStack - Free trial, then $29-99/month
    • Use if you need cross-browser testing on real devices
  3. Your Own Devices (Recommended)

    • iOS Safari (iPhone/iPad)
    • Android Chrome
    • Desktop browsers (Chrome, Firefox, Safari)
    • Most reliable for catching real issues

Test Checklist:

  • Navigation works on mobile
  • Dark mode toggle accessible
  • Text readable without zooming
  • No horizontal scroll
  • Touch targets ≥ 44×44px
  • Forms usable on mobile (if applicable)
Staying Updated with Astro Releases

Current version: Astro v7.4.1 (see the starter’s package.json for the exact version)

Monitoring updates:

Astro releases new versions regularly. Stay informed to benefit from improvements and avoid breaking changes.

Update strategy:

  1. Follow release channels:

  2. Before upgrading:

    • Review Astro upgrade guide
    • Check for breaking changes in the changelog
    • Test in a separate branch first
  3. Safe upgrade process:

    • Create a new branch: git checkout -b upgrade-astro
    • Update dependencies: pnpm update astro
    • Run build: pnpm run build
    • Test locally: pnpm run preview
    • Fix any breaking changes
    • Merge when stable

Staying updated:

Terminal window
# Check for updates
pnpm outdated
# Update Astro (minor versions)
pnpm update astro
# Update all dependencies
pnpm update
# Major version upgrade (test first!)
pnpm add astro@latest

Cause: Platform doesn’t have pnpm installed

Fix: Update build command to install pnpm first:

Terminal window
npm install -g pnpm && pnpm run build

Most platforms enable Corepack and honour the packageManager field in package.json (pnpm@11.27.1), in which case pnpm is already available. Do not switch to npm run build: the build script shells out to pnpm run env:validate and pnpm run tokens:build, so the template is pnpm-only (constitution rule 6).

Cause: Missing token files in repository

Fix:

  1. Verify tokens/base.json and tokens/semantic.json exist locally
  2. Ensure they’re committed to Git:
Terminal window
git add tokens/
git commit -m "fix: add token files"
git push

Cause: Path aliases not resolved

Fix: Ensure tsconfig.json has proper paths configuration (should be default in template). If missing, add:

{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@layouts/*": ["src/layouts/*"],
"@utils/*": ["src/utils/*"]
}
}
}

Fix: Verify the SITE_URL environment variable on your platform matches the deployment URL exactly (including https://)

Terminal window
# ✅ Correct
SITE_URL=https://my-project.pages.dev
# ❌ Incorrect
SITE_URL=my-project.pages.dev # Missing https://
SITE_URL=http://my-project.pages.dev # Wrong protocol

Fix: Ensure platform build settings use dist as output directory

Fix: Don’t hardcode site or base in astro.config.mjs — both are derived at config-load time: site from SITE_URL (or PUBLIC_SITE_URL) and base from DEPLOY_TARGET:

// astro.config.mjs (already in the template — do not replace with literals)
const envSite = process.env.SITE_URL || process.env.PUBLIC_SITE_URL;
const isGhPages = process.env.DEPLOY_TARGET === "gh-pages";
const base = isGhPages ? `/${pkg.name}` : "/";
  • Blank page at https://<github-username>.github.io/<repo-name>/ with 404s for /_astro/* assets → the build ran without DEPLOY_TARGET=gh-pages. The shipped workflow sets it; a local build needs it in the environment.
  • Blank page on a custom domain or a root-path host → the build ran with DEPLOY_TARGET=gh-pages, so every asset URL carries /<repo-name>. Unset it (on GitHub Pages, set the SITE_URL repository variable and the workflow drops it for you).
  • Renamed the repo? Update the name field in package.json — that is where the /<repo-name> base comes from.

Fix: Use Astro’s image component and relative imports:

---
// ✅ Correct
import { Image } from 'astro:assets';
import myImage from '@/assets/image.jpg';
---
<Image src={myImage} alt="Description" />
<!-- ❌ Incorrect -->
<img src="/src/assets/image.jpg" alt="Description" />

Fix: The build script automatically compiles tokens. If styles are still broken:

Terminal window
# Test locally first
pnpm run build
pnpm run preview

If it works locally but not on the platform, check:

  • Build logs for token compilation step
  • Ensure tokens/ directory is committed to Git
  • Verify platform is using pnpm run build (not a custom command)

Cause: Font files or Fonts API config out of sync

Section titled “Cause: Font files or Fonts API config out of sync”

Fix: The template loads fonts through Astro’s Fonts API — the .woff2 files are vendored in src/assets/fonts/ and registered in astro.config.mjs via fontProviders.local(). Verify:

Terminal window
ls src/assets/fonts/*.woff2
  • Font files exist in src/assets/fonts/ and are committed to Git
  • The fonts entries in astro.config.mjs point at the correct file paths
  • No manual <link rel="preload"> tags are needed — the Fonts API generates preload tags automatically
  1. Check build logs on your platform dashboard for detailed error messages
  2. Review deployment guide: Phase 10: Deployment
  3. Common issues: FAQ
  4. Search existing issues: GitHub Issues
  5. Ask for help: GitHub Discussions

Now that you’re deployed, choose your path based on your goals:

Best for: Blogs, portfolios, marketing sites

  1. Creating Your First Page
  2. Content Collections Guide
  3. Add blog posts or projects
  4. Customize page layouts

Time: 1-2 hours to first content page

Best for: Unique branding, custom themes

  1. Design Tokens Guide
  2. Customize colors, typography, spacing
  3. Create custom components
  4. Build design system

Time: 2-4 hours for basic customization

Best for: Complex sites, interactive elements

  1. Component Patterns
  2. Phase 5: Components
  3. Add interactive islands
  4. Implement advanced features

Time: 4-8 hours for advanced features

Best for: Production-ready, feature-complete sites

  1. Implementation Guides overview — one progressive path in three tiers (ADR-033)
  2. Build tier (Phases 5-8): components, sections, content, QA — scope each phase to Essential / Recommended / Advanced
  3. Polish tier (Phases 9-12): performance, deployment, documentation, post-launch
  4. Stop when you’ve reached your goals

Time: 2-6 weeks depending on how far into the Polish tier you go

Actual times for this guide:

PhaseTime
Setup & Personalization20-30 min
Git & Repository Setup5-10 min
Platform Deployment10-20 min
Verification & Testing5-10 min
Custom Domain (optional)+15 min
Total45-75 min

Your site is now live! You’ve successfully:

  • ✅ Personalized your branding
  • ✅ Deployed to production
  • ✅ Verified performance
  • ✅ Tested across devices

We’d love to see what you’ve built:

Your deployment is just the beginning. Explore the implementation guides, customize the design system, and let’s build something amazing.