# Deploy static sites

> Deploy Astro, Vite, React, Vue and plain HTML sites with Falak — built on the builder, served by Caddy with HTTPS, SPA fallback and custom 404 pages.

Source: https://falak.sh/docs/deploy/static-sites/

A static site is built once on the builder and served by Caddy on your servers. There is no process to supervise. Single-page apps work out of the box.

## Prerequisites

- A server of type **app** or **web** (any server that serves HTTP).
- One of:
  - a Vite (React, Vue, Svelte, Solid, …), Create React App or Astro project with a `build` script and **no `start` script**;
  - plain HTML with `index.html` (or `public/index.html`) in the repository root.

## Deploy

1. **+ Create → Git repository**, pick the repository.
2. Choose the **Static site** preset. The runtime is **Static**.
3. Pick servers and a domain, then **Deploy**.

## What gets published

| Project | Detected output directory |
|---|---|
| Vite (React, Vue, Svelte, …) | `dist` |
| Create React App | `build` |
| Astro (without `@astrojs/node`) | `dist` |
| `index.html` in the root | the repository root |
| `public/index.html` | `public` |
| Other frameworks with the Static preset | the first of `dist`, `build`, `out`, `public` that exists in the repository before the build |

The builder installs dependencies, runs `npm run build` (or the pnpm, yarn or bun equivalent) with `NODE_ENV=production`, and packages only the output directory.

The output directory is decided **before** the build runs. If your framework builds into a directory that is not detected (for example `_site` or `.output/public`), the whole app root is packaged. Set the site's **web directory** (under **Settings → Build**) to the output folder, for example `_site`, so Caddy serves from there.

## Build-time variables

Only variables with a public prefix reach the build: `VITE_`, `NEXT_PUBLIC_`, `NUXT_PUBLIC_`, `PUBLIC_`, `REACT_APP_`. Expose any other variable to the deploy script to make it available to the build (for example Astro's `SITE_URL`). See [Builds](/docs/concepts/builds/#build-time-variables).

```dotenv title="Site variables"
VITE_API_URL=https://api.example.com
PUBLIC_PLAUSIBLE_DOMAIN=example.com
```

## How requests are served

For every request Caddy tries, in order:

1. the exact file, or the directory's `index.html`;
2. `/404.html` with status **404**, if your site has one;
3. `/index.html` for paths **without a file extension**, so client-side routes like `/dashboard/settings` survive a reload (SPA fallback);
4. otherwise a 404.

A missing asset like `/assets/app.js` stays a 404 instead of returning your HTML. `.env` and `.git` are never served.

Add headers, redirects, basic auth or IP rules under **Settings → Networking**. See [Routing rules](/docs/guides/routing-rules/).

## Deploy script

```bash title="Deploy script (Static preset)"
$FALAK_FETCH

$FALAK_ACTIVATE
```

Releases switch atomically. Static sites have no restart phase, and the preset sets no health check path; add one under **Settings → Deploy** if you want Falak to verify each release.

## Next steps
