Deploy an Astro Site on Vercel: the 10-Minute Path (2026)

Ship Astro on Vercel with the exact Astro 5 astro.config.mjs, Node 22 pin, vercel.json cache headers, CLI commands, and DNS + SSL verification — no detours.

A static Astro site deploys to Vercel with zero configuration — that part really is fast. The 10 minutes go into the four things Vercel does not guess for you: the site URL, the trailing-slash policy, the Node version, and your custom domain’s DNS. Get those right once and every future push is a one-line deploy. Below is the exact astro.config.mjs for Astro 5, a minimal vercel.json, the CLI commands, and the DNS records that actually provision SSL — verified against Vercel and Astro docs as of June 2026.

TL;DR

  • A static Astro site needs no adapter. You only install @astrojs/vercel if you want SSR, ISR, Vercel Image Optimization, or Vercel Web Analytics.
  • In Astro 5 the import is unified: import vercel from '@astrojs/vercel', with output: 'static' or output: 'server'. The old output: 'hybrid' was removed — 'static' now covers mixed sites, and you opt individual routes out with export const prerender = false.
  • Pin Node in package.json ("engines": { "node": "22.x" }). Vercel’s default is now 24.x (since Feb 2026), with 22.x and 20.x also available — pinning prevents a silent runtime bump from breaking a build that passed last week.
  • Apex domain → A 76.76.21.21; wwwCNAME cname.vercel-dns-0.com. SSL provisions automatically, usually within minutes.
  • Hobby is free but non-commercial only. Any site that earns money (ads, affiliates, a product) must be on Pro at $20 per seat/month.

Static or server: pick before you touch config

Vercel auto-detects Astro and sets the build command to astro build and the output directory to dist with no input from you. The only architectural choice is rendering mode:

ModeoutputAdapter needed?Use it for
Static (default)'static'NoBlogs, docs, marketing, content sites
Static + Vercel features'static'Yes (@astrojs/vercel)Static site that also wants Vercel Image Optimization or Web Analytics
On-demand (SSR)'server'Yes (@astrojs/vercel)Auth, dashboards, personalized or per-request pages

For the vast majority of content and indie projects, you want plain 'static' and no adapter at all. Adding the adapter when you do not need SSR just slows builds and buys you nothing.

Before you start

  • Repo pushed to GitHub, GitLab, or Bitbucket; a Vercel account linked to it.
  • Node version pinned in package.json (covered below).
  • Custom domain ready (optional, but do it now so SSL has time to provision).

Step by step

1. Pin the essentials in astro.config.mjs

import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import mdx from '@astrojs/mdx';

export default defineConfig({
  site: 'https://yourdomain.com',   // required for sitemap + canonical URLs
  trailingSlash: 'always',          // pick one policy and never mix it
  build: { format: 'directory' },
  output: 'static',                 // 'static' is the default in Astro 5
  integrations: [mdx(), sitemap()],
});

site is the single most-forgotten setting. Without it, @astrojs/sitemap and your canonical tags emit localhost or the *.vercel.app preview host, which quietly breaks SEO after you go live.

2. (Optional) vercel.json for cache headers and redirects

{
  "cleanUrls": true,
  "trailingSlash": true,
  "redirects": [
    { "source": "/blog/:path*", "destination": "/articles/:path*", "permanent": true }
  ],
  "headers": [
    {
      "source": "/_astro/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
      ]
    }
  ]
}

Two cautions from Vercel’s own Astro docs: do not use vercel.json to rewrite URL paths for Astro — rewrites only work for static files and are not officially supported, so use Astro’s redirects config or Vercel Routing Middleware instead. And keep trailingSlash consistent between vercel.json and astro.config.mjs, or you generate a wave of unnecessary 308 redirects.

3. Pin the Node version in package.json

{
  "engines": { "node": "22.x" },
  "scripts": {
    "build": "astro build",
    "preview": "astro preview"
  }
}

Vercel’s default build runtime is 24.x as of February 2026 (24.x, 22.x, and 20.x are the supported lines). The engines.node field overrides the project-settings default, so a passing build stays reproducible even when Vercel rolls the default forward. 22.x is the safe, current LTS choice for most Astro projects.

4. Push the repo and import on Vercel

UI flow: Add New → Project → Import. Or from the project root via CLI:

npm install -g vercel
vercel login
vercel link          # connect the local repo to a Vercel project
vercel --prod        # build + deploy to production
# Production: https://your-project.vercel.app

5. SSR only (skip if you are static)

If — and only if — you set output: 'server', install the adapter. In Astro 5 it is a single unified import:

npm install @astrojs/vercel
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';

export default defineConfig({
  output: 'server',
  adapter: vercel(),
});

For a mostly-static site with a few dynamic routes, keep output: 'static' and add export const prerender = false; to the frontmatter of just those pages. Astro 5 server-renders those routes as Vercel Functions and prerenders everything else — this replaces the old 'hybrid' mode.

6. Add environment variables for Production and Preview

vercel env add SITE_URL production
# https://yourdomain.com
vercel env add OPENAI_API_KEY production
# paste secret

In the UI: Project → Settings → Environment Variables, and check both Production and Preview for any variable that must exist in both environments. Variables left only in a local .env are the most common cause of “works locally, fails on Vercel.”

7. Verify the build output and first deploy

npm run build
ls dist/             # confirm sitemap-index.xml, index.html, _astro/
vercel --prod

Then visit https://your-project.vercel.app, click around, and confirm headers and sitemap from the terminal:

curl -sI https://your-project.vercel.app/ | grep -i cache-control
curl -sI https://your-project.vercel.app/sitemap-index.xml | head -1

8. Add the custom domain and DNS

Settings → Domains → add yourdomain.com. Vercel shows the records to set at your DNS provider. The current general-purpose values are:

RecordHostValue
A@ (apex)76.76.21.21
CNAMEwwwcname.vercel-dns-0.com

Vercel migrated the recommended CNAME target from cname.vercel-dns.com to cname.vercel-dns-0.com; the older value still resolves, but use what your dashboard shows. For the exact project-specific records, run vercel domains inspect yourdomain.com. SSL is issued automatically once DNS propagates — usually within minutes, occasionally up to an hour.

Hobby vs Pro: the licensing fact people miss

Vercel’s Hobby plan is free, but it is licensed for personal, non-commercial use only. The moment a site generates revenue — ads, affiliate links, a paid product, even a client project — Vercel’s terms require Pro at $20 per seat/month (per the Vercel pricing page). For a hobby blog Hobby is fine; for a money page, budget for Pro. If commercial use on a free tier is a dealbreaker, Firebase Hosting’s Spark tier permits commercial use at no cost.

Implementation checklist

  • astro.config.mjs sets site, trailingSlash, and an explicit output.
  • package.json pins Node via engines.node ("22.x").
  • Environment variables exist for both Production and Preview.
  • vercel.json (if used) matches astro.config.mjs on trailing slash and cleanUrls.
  • No @astrojs/vercel adapter unless you are on output: 'server' or using a Vercel-only feature.
  • Custom domain shows a green check and a valid certificate.
  • On a commercial site, the project is on a Pro plan.

After-launch verification

  • curl -sI returns 200 on the custom apex domain (not a redirect loop).
  • sitemap-index.xml is reachable at the production URL.
  • Google Search Console’s submitted-vs-indexed count tracks your sitemap entry count after the first crawl.
  • Lighthouse SEO scores 100 on at least one sample article.

Common pitfalls

  • site missing in astro.config.mjs. Sitemap and canonical URLs come out as localhost or the preview host. Always the first thing to check after a launch.
  • Adapter installed without SSR. Adding @astrojs/vercel on a static output: 'static' site slows builds for no benefit. Remove it unless you need SSR, ISR, or a Vercel feature.
  • Stale output: 'hybrid'. Astro 5 removed 'hybrid'; the build errors out. Switch to 'static' and per-route export const prerender = false.
  • Env vars only in .env. Production fails with missing-variable errors. Add them in Vercel for Production and Preview.
  • Conflicting trailing-slash settings. cleanUrls: true plus trailingSlash: 'always' produces extra 308s. Pick one policy across both files.
  • Rewrites in vercel.json. Path rewrites are unsupported for Astro and behave inconsistently — use Astro redirects or Routing Middleware.
  • Node bumped under you. Without engines.node, a build that passed on 22.x can break when Vercel’s default moves to 24.x.

FAQ

  • Do I need the @astrojs/vercel adapter?: No, not for a static site. You only need it for output: 'server' (SSR), ISR, Vercel Image Optimization, or Vercel Web Analytics. A plain static Astro site deploys with zero config.
  • What happened to output: 'hybrid'?: Astro 5 merged it into 'static'. Keep output: 'static' and add export const prerender = false to any route that should render on demand. Remove any leftover 'hybrid' or the build fails.
  • Which Node version should I pin?: "engines": { "node": "22.x" }. Vercel supports 24.x (the default since Feb 2026), 22.x, and 20.x. Pinning keeps builds reproducible when Vercel moves the default.
  • Will Vercel optimize images automatically?: Yes. Astro’s Image component is optimized on-demand on Vercel with zero config for static sites; the @astrojs/vercel adapter’s imageService option adds the same for SSR.
  • How do preview deploys work?: Every git push to any branch gets its own preview URL, and pull requests get an auto-comment with the link. Previews are noindex by default.
  • Can I run a commercial site on the free Hobby plan?: No. Hobby is personal, non-commercial use only. Revenue-generating sites must be on Pro at $20 per seat/month.
  • Can I deploy from the CLI without GitHub?: Yes. vercel --prod from the project root deploys without any git remote.

Tags: #Indie dev #Vercel #Hosting #Astro #Getting started #Workflow