Building for Production
When you are ready to ship, astro build compiles your project into a set of optimized, static assets that any host can serve. Astro’s defining principle—zero JavaScript by default—shows up most clearly here: the build renders every component to HTML ahead of time and only ships client-side JavaScript for the islands you explicitly hydrate. This page walks through what the build emits, how to control the output directory, and how to preview the result locally so you catch problems before they reach production.
Running the build
The production build is a single command. From your project root, run:
npm run build
This invokes astro build (defined in your package.json scripts). Astro renders all pages, bundles and minifies your CSS and JavaScript, optimizes images, and writes everything to the output directory.
Output:
astro v5.4.0 building static entrypoints...
✓ Completed in 842ms.
building client (vite)
✓ 6 modules transformed.
dist/_astro/Counter.D8kQv2.js 1.18 kB │ gzip: 0.67 kB
✓ built in 311ms
generating static routes
▶ /index.html (+12ms)
▶ /about/index.html (+4ms)
▶ /blog/[slug]/index.html
├─ /blog/hello-world/index.html (+9ms)
└─ /blog/astro-tips/index.html (+3ms)
✓ Completed in 38ms.
Complete!
Notice that only the interactive Counter island produced a JavaScript bundle. Static pages with no client:* directives ship pure HTML and CSS.
What the build emits
By default the build writes to a dist/ folder at your project root. The exact structure depends on your rendering mode.
| Output mode | What is generated | Where it runs |
|---|---|---|
static (default) | Pre-rendered .html files plus hashed assets | Any static file host or CDN |
server | A server entry point plus pre-rendered static pages | A Node, edge, or serverless adapter |
A typical static build produces:
dist/
├── _astro/ # hashed, minified JS and CSS for islands
├── index.html
├── about/
│ └── index.html
└── blog/
└── hello-world/
└── index.html
The _astro/ directory holds fingerprinted (content-hashed) asset files, so you can cache them aggressively—changing a file changes its filename, busting the cache automatically.
Configuring the output directory
You can change where the build writes its files with the outDir option in astro.config.mjs. The build.assets option controls the name of the hashed-assets subfolder.
import { defineConfig } from "astro/config";
export default defineConfig({
outDir: "./build",
build: {
assets: "static",
// "directory" -> /page/index.html (default), "file" -> /page.html
format: "directory",
},
});
The build.format option matters for how URLs resolve on your host. directory produces /about/index.html (clean URLs like /about/), while file produces /about.html. Choose whichever matches your host’s routing conventions.
Astro empties the output directory at the start of every build. Never put source files you care about in
dist/(or your customoutDir)—they will be deleted.
Previewing the build locally
The dev server (astro dev) uses on-demand compilation and is not representative of production. To inspect the actual built output, use the preview server:
npm run build
npm run preview
Output:
┃ Local http://localhost:4321/
┃ Network use --host to expose
watching for file changes...
astro preview serves the contents of dist/ over HTTP exactly as a static host would, which lets you verify asset paths, redirects, and hydration before deploying.
astro previewonly serves a static build out of the box. If you use an SSR adapter, preview behavior depends on the adapter—some (like Node) support it, while serverless adapters do not. Check your adapter’s docs.
Setting the site and base
For correct canonical URLs, sitemaps, and absolute asset links, set site to your production domain. If you deploy under a subpath, also set base.
import { defineConfig } from "astro/config";
export default defineConfig({
site: "https://example.com",
base: "/docs", // only if the app lives at example.com/docs
});
When base is set, reference internal links and assets relative to it using import.meta.env.BASE_URL:
---
const base = import.meta.env.BASE_URL;
---
<a href={`${base}/about`}>About</a>
Best practices
- Always set
site(andbasewhen deploying to a subpath) so generated URLs and sitemaps are correct. - Preview every build with
astro previewbefore deploying; the dev server can hide path and hydration issues. - Keep islands minimal—add
client:*directives only where interactivity is required to preserve the zero-JS-by-default baseline. - Rely on content-hashed filenames in
_astro/to set long-lived cache headers on assets safely. - Treat the output directory as disposable; commit only source, and let CI run
astro buildfresh each time. - Run
astro checkin CI alongside the build to catch type and content-collection errors before shipping.