hosting
How to host an Astro dist folder
By PreviewSend Team · Jul 27, 2026 · 7 min read

To host an Astro dist folder, build the project so Astro writes static HTML to dist/, confirm every route was prerendered rather than left for a server, then zip the contents of dist and upload that archive to a static host. Astro prerenders your whole site by default, so a standard build is usually ready to serve as plain files.
Build, check the production output locally, then create the archive:
npm run build # prerenders your site into ./dist
npm run preview # serves the built dist locally so you can check it
cd dist
zip -r ../site.zip .
Upload site.zip and you have a URL. Before you do, check where Astro wrote the output, whether every route became a file, and why a page visible in development might be absent from dist.
Where Astro writes the build
npm run build compiles your project into static HTML and bundled assets. Astro's deployment guide describes this as building your site to static files by default, and it writes them to a dist folder in your project root.
That location isn't hard-coded. The outDir option sets the directory astro build writes to and defaults to ./dist. If your astro.config.mjs sets outDir to something else, the build lands there instead. Open the config before you go looking for the folder.
Run the build with whatever your lockfile points to: package-lock.json means npm run build, pnpm-lock.yaml means pnpm build, yarn.lock means yarn build, and bun.lock means bun run build. The output folder is the same either way.
What has to be true to host an Astro dist folder as static files
Astro's current output setting has two targets, static and server, and only a fully prerendered build produces something a file host can serve on its own. By default, Astro prerenders pages, routes, and endpoints at build time as static HTML. That's the output a ZIP host wants. The moment a route is set to render on demand, that route needs a server process, and no amount of zipping changes it.
Match what your project uses against this table:
| What your Astro project uses | Ends up in dist as static files? | Why |
|---|---|---|
| Pages prerendered by default | Yes | Astro renders them to HTML during the build |
Dynamic routes with getStaticPaths() | Yes | Every path is generated at build time |
| Markdown or content-collection pages | Yes | They're compiled to HTML during the build |
A route with export const prerender = false | No | It renders per request and needs an adapter |
output: 'server' in the config | Not as a whole | Routes render on demand by default; only routes with prerender = true become static files |
Server islands (server:defer on a component) | No | The deferred component renders on a server |
| Actions or server endpoints called at runtime | No | They execute server code for each request |
If every row your project touches is a "Yes," the build is static and this workflow fits. A single "No" means that piece needs a runtime host, even when the rest of the site is plain HTML. For anything not listed, ask whether it runs while astro build is creating files or after a visitor requests a page. The framework-agnostic static-versus-dynamic guide applies that test to Next.js, Vite, and AI-builder exports.
Run the build and inspect dist
Don't upload a folder you haven't opened. After the build, look inside dist:
dist/
├── index.html
├── about/
│ └── index.html
├── blog/
│ └── first-post/
│ └── index.html
├── _astro/
│ ├── about.DpR2s9x1.css
│ └── client.Cb3f0aQ.js
└── favicon.svg
A few Astro specifics are worth recognizing here:
- Routes are folders, not flat files. Astro's default
build.formatisdirectory, so/aboutbecomesabout/index.htmlrather thanabout.html. A host that serves directory indexes returns the right page when someone visits/about. _astro/holds the bundled CSS and JavaScript. That's Astro's default asset folder. A hashed filename changes when that bundled asset's contents change, which lets a new upload bypass stale copies of the old asset.favicon.svgsits at the root untouched. Files in yourpublic/directory are copied into the build as-is, without bundling.
Then preview it. npm run preview (which runs astro preview) serves the contents of dist locally so you can click through the exact files you're about to zip. Open the URL it prints, walk the routes, and watch the Network tab for failed asset requests. Astro is explicit that preview is for local inspection, not production hosting, so treat it as the last check before the upload rather than the deployment itself.
Why a route can be missing from dist
You see a page in npm run dev, build, and it isn't in dist. In static mode this almost always traces back to a dynamic route.
A file like src/pages/blog/[slug].astro doesn't know which slugs exist. Astro's static routing docs require a dynamic route to export a getStaticPaths() function so every path is known at build time:
---
export function getStaticPaths() {
return [{ params: { slug: 'first-post' } }, { params: { slug: 'second-post' } }]
}
---
Astro builds one HTML file per object that function returns. A slug you forgot to include there simply doesn't get a page. If the route can't enumerate its paths ahead of time because it depends on request data, it isn't a static route at all, and it belongs in the on-demand category from the table above.
Choose a runtime host when Astro needs an adapter
If the table turns up an on-demand feature, stop before packaging dist. Add the adapter for your destination and deploy through that platform's Astro workflow instead. An adapter can still write files into the output directory, but those files include code for a server, serverless function, or edge runtime. A static ZIP host cannot execute them.
The dividing line is whether part of the app runs code for each visitor. A static frontend can call a separately hosted API over the network, but the server-rendered part of an Astro app has to run somewhere that executes it.
A note on the base path
Astro serves your site from the domain root by default, and PreviewSend serves the build so that default is correct. If you set base to a subpath for a different host, Astro expects you to prefix your own internal links and asset URLs with that base. Set base, update hand-written links to use that prefix, then rebuild so the corrected paths are written into dist. The Vite dist-folder guide covers the same subpath trap in more depth if you're comparing the two build tools.
Zip the contents, then upload
Package the build so index.html lands at the top of the archive:
cd dist
zip -r ../site.zip .
The trailing . compresses the folder's contents, not the folder itself. Without a terminal, open dist, select everything inside, and compress the selection. Keeping index.html at the archive root is the most portable layout. PreviewSend can use the shallowest nested index.html, but other hosts may be stricter; the ZIP hosting guide covers the layout checks behind "index.html not found" errors.
With site.zip holding a root index.html, the upload is short. Static hosts that accept prebuilt files directly, without a repository or CI pipeline, include Cloudflare Pages Direct Upload and Netlify Drop; their access controls and limits vary. For a client-facing draft that needs a stable review URL, start a PreviewSend workspace and upload the archive (up to 100 MB compressed and 256 ZIP entries). It validates the ZIP, extracts the files, serves the nested route directories your Astro build produced, and returns a stable URL. It does not execute Astro server code, so an on-demand route from the table above still won't run.
Because the URL is stable, updating the site means rebuilding, re-zipping dist, and uploading again. The new build becomes the active version at the same address, so everyone holding the link sees the current site without a new attachment. New projects also turn on account-free review by default: a reviewer can pin comments or request changes on the page without a PreviewSend account. If the draft needs to stay private, add a project password, which is the actual access gate. A noindex header asks search engines to stay away, but it's a request, not access control, so anyone with the link can still open an unprotected preview.
Before you send the link, open a nested route such as /about, reload it directly, and check the browser's Network tab once more. That catches the two failures a homepage-only check misses: directory routes that return 404 and _astro assets requested from the wrong path.
FAQ
Where does Astro put the build output?
Running the build writes a dist folder in your project root. That default comes from the outDir setting, which resolves to ./dist unless a project overrides it. If your astro.config file sets outDir to something else, the compiled site lands there instead, so open the config before you assume the folder name.
Do I need an Astro adapter to host the dist folder?
Not for a fully static site. Astro prerenders every page by default, so a standard build is plain HTML a file host can serve. You need an adapter only when a route opts out of prerendering with export const prerender = false, when the config uses output: server, or when a component uses server islands. Those parts run on a server and cannot live in a ZIP.
A page shows in dev but is missing from dist. Why?
Two common causes. A dynamic route such as [slug].astro only builds the paths its getStaticPaths() function returns, so a slug missing from that list produces no HTML. Or the route opted into on-demand rendering, in which case it never becomes a static file and needs a server runtime.
Should I zip the dist folder or the files inside it?
Zip the contents so index.html sits at the top of the archive rather than inside a dist/ wrapper. That layout is the most portable across static hosts. PreviewSend can recover the shallowest nested index.html, but keeping it at the archive root avoids relying on host-specific fallback behavior.
Does astro preview host my site?
No. It serves the built dist folder locally so you can inspect the production output before shipping it. It runs on your machine and stops when you close the terminal. Use it as a final check, then upload the same dist to a real host.
Have a site to host? Upload it and get a live link in seconds.
Get it free