NNicheStackTutorials
← All tutorials
Astro

Deploy Astro to Netlify Free Tier (Config That Actually Works)

netlify.toml, build settings, environment variables, and fixing the 'Page not found' on refresh bug.

·10 min read·Astro
Deploy Astro to Netlify Free Tier (Config That Actually Works) cover

Tested on: Astro 5.7, Netlify free tier, Node 22 Deploy time: ~90 seconds. Cost: $0.

netlify.toml

[build]
  command = "npm run build"
  publish = "dist"

[build.environment]
  NODE_VERSION = "22"

[[headers]]
  for = "/_astro/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

package.json scripts

{
  "scripts": {
    "build": "astro build",
    "preview": "astro preview"
  }
}

Netlify auto-detects Astro sometimes. Don't trust it — explicit netlify.toml wins.

Environment variables

Site settings → Environment variables:

PUBLIC_SITE_URL=https://myblog.netlify.app

astro.config.mjs:

export default defineConfig({
  site: import.meta.env.PUBLIC_SITE_URL || 'http://localhost:4321'
});

RSS feeds and canonical URLs need the production URL.

Error — build succeeds, site blank

Publish directory was set to .astro instead of dist

Netlify UI overrides netlify.toml if you set publish dir manually. Clear UI setting or match dist.

Error — 404 on direct URL access

Astro static outputs about/index.html. Netlify serves it for /about and /about/.

If using output: 'server' or hybrid — different story. For static:

export default defineConfig({ output: 'static' });

No _redirects SPA fallback needed.

Deploy preview

Connect GitHub repo. Every PR gets preview URL. Check:

curl -I https://deploy-preview-42--myblog.netlify.app/about/

Custom domain (free tier)

Domain settings → Add custom domain → Netlify DNS or external CNAME to myblog.netlify.app.

HTTPS auto-provisioned via Let's Encrypt.

Build minute budget

Free tier: 300 build minutes/month
My Astro site build: ~1.5 min
~200 deploys/month headroom

Checklist

  • publish = "dist"
  • site in astro.config.mjs
  • NODE_VERSION pinned
  • /_astro/* cache headers
  • Test one deep link after deploy

Tags: AstroNetlifyDeploymentFree Tier