Astro on Vercel is genuinely a 10-minute setup if you do not get distracted by every checkbox. This walkthrough is the shortest path that still gets you HTTPS, a custom domain, image optimization, and preview deploys — with the exact astro.config.mjs, vercel.json, and CLI commands.
Background
Vercel detects Astro automatically and uses sensible defaults. The two settings that actually matter are output mode (static vs server) and the adapter (none for static, @astrojs/vercel for server). Most content sites should stay static. Everything else Vercel handles for you.
Before you start
- Repo on GitHub/GitLab/Bitbucket; Vercel account linked.
- Node version pinned in
package.json. - Custom domain ready (optional but recommended).
Step by step
- Pin the basics 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
trailingSlash: 'always',
build: { format: 'directory' },
output: 'static', // for content sites
integrations: [mdx(), sitemap()],
});
- Optional
vercel.jsonfor cache headers, redirects, and clean URLs:
{
"cleanUrls": true,
"trailingSlash": true,
"redirects": [
{ "source": "/blog/(.*)", "destination": "/articles/$1", "permanent": true }
],
"headers": [
{
"source": "/_astro/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
]
}
]
}
- Pin Node in
package.jsonto avoid version surprises:
{
"engines": { "node": "20.x" },
"scripts": {
"build": "astro build",
"preview": "astro preview"
}
}
- Push the repo + import on Vercel. Either UI flow (Add New → Project → import) or CLI:
npm install -g vercel
vercel link # link the local repo to a Vercel project
vercel --prod # deploy to production
# Production: https://your-project.vercel.app
- For SSR (rare on content sites), add the Vercel adapter:
npm install @astrojs/vercel
// astro.config.mjs
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
// ...
output: 'server',
adapter: vercel(),
});
Skip this section if you are static.
- 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 → check Production + Preview boxes for each variable that needs to exist in both.
- Verify build output + first deploy:
npm run build
ls dist/ # confirm sitemap.xml, index.html, _astro/
vercel --prod
Then visit https://your-project.vercel.app and click around. Test:
curl -sI https://your-project.vercel.app/ | grep -i cache-control
curl -sI https://your-project.vercel.app/sitemap-index.xml | head -1
- Add the custom domain. Settings → Domains → add
yourdomain.com. Follow the DNS prompts (typically apexA 76.76.21.21andCNAME www → cname.vercel-dns.com). SSL provisions automatically; usually < 1 hour.
Implementation checklist
astro.config.mjssetssite,trailingSlash, and a fixed output mode.package.jsonpins Node viaengines.node.- Environment variables added for Production AND Preview.
vercel.json(if used) is consistent withastro.config.mjson trailing slash / cleanUrls.- Custom domain has green check, SSL valid.
After-launch verification
curl -sIreturns 200 on the custom domain.dist/sitemap-index.xmlis reachable at production URL.- Search Console “Submitted” matches the sitemap entry count after first crawl.
- Lighthouse SEO = 100 on at least one sample article.
Common pitfalls
- Forgetting to set
siteinastro.config.mjs— sitemap and canonical URLs end up withlocalhostor the preview URL. - Adding the
@astrojs/verceladapter when you do not need SSR — slower builds, no benefit. - Leaving environment variables in
.envand never adding them to Vercel — production fails with missing-var errors. - Setting build command to
npm run buildwhenvercel.jsonoverrides it — check which one wins. - Trying to deploy
node_modulesaccidentally —.vercelignoreor.gitignoreshould handle it. cleanUrls: trueinvercel.jsonpaired withtrailingSlash: 'always'in Astro — generates unnecessary 308s. Pick consistently.
FAQ
- Do I need the
@astrojs/verceladapter?: Only if you setoutput: 'server'or'hybrid'. For a fully static site, the adapter is not needed. - Will Vercel optimize my images automatically?: Yes, via Astro’s built-in
<Image>component on a deployment, or via@astrojs/vercel’s image service if you opt in. - How do preview deploys work for Astro?: Every git push (any branch) gets a preview URL. Pull requests get a comment with the URL. They are noindex by default.
- What if my build fails on Vercel but works locally?: Most likely Node version or missing env var. Lock Node version in
package.jsonengines field; check Vercel build logs. - Can I deploy from the CLI without GitHub?: Yes —
vercel --prodfrom the project root works without a git remote.
Related
- What is Vercel
- Vercel build failed common causes
- Vercel content site go-live checklist
- Vercel custom domain
- Is Vercel good for content sites
Tags: #Indie dev #Vercel #Hosting #Astro #Getting started #Workflow