> ## Documentation Index
> Fetch the complete documentation index at: https://bunny.net/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Host a static site on Bunny Storage

> Deploy static sites and single-page apps to Bunny Storage and serve them through Bunny CDN, with the Bunny CLI or by hand.

A static site on bunny.net is a storage zone that holds your built files, with a pull zone in front that serves them from the CDN. You can set that up with the [Bunny CLI](https://bunny.net/docs/cli.md), which detects your framework, runs the build, and uploads the output, or you can create the zones in the dashboard and upload the files yourself.

## Deploy your site

> [tab] Bunny CLI
>
> > [!WARNING]
> >
> > `bunny sites` is in [Public Preview](https://bunny.net/docs/product-release-stages.md#stage-2-public-preview)
> > and available only in the Bunny CLI. It's in active development, so commands,
> > flags, and behaviour may change. Share feedback on
> > [Discord](https://discord.gg/bunnynet). The storage zone and pull zone behind
> > each site appear in the dashboard under **Storage** and **CDN**.
>
> From your project root:
>
> ```bash theme={null}
> bunny sites create my-site
> bunny sites deploy --build
> ```
>
> `bunny sites create` makes the storage zone and pull zone and links your directory to the site. `bunny sites deploy --build` detects your framework, runs its build with the package manager from your lockfile (Bun, pnpm, Yarn, or npm), and publishes the output directory. Each deploy is kept, so `bunny sites deployments publish --previous` rolls back to the last one.
>
> Run `bunny sites ci init` to add a GitHub Actions workflow that deploys on every push to `main`. See [`bunny sites`](https://bunny.net/docs/cli/commands/sites) for every command.

> [tab] Manually
>
> **1. Build your site**
>
> From your project root, run your framework's build command. The [framework guides](#framework-guides) list the command and output directory for each framework.
>
> **2. Create a storage zone**
>
> In the [bunny.net dashboard](https://dash.bunny.net), go to **Storage** and click **Add Storage Zone**. Give it a name, pick the main region closest to your audience, and click **Add Storage Zone**.
>
> **3. Upload your files**
>
> Open the storage zone's file manager and upload the contents of your output directory to the root of the zone. To script uploads, use the [Storage HTTP API](https://bunny.net/docs/storage/http.md).
>
> **4. Create a pull zone**
>
> Go to **CDN** and click **Add Pull Zone**. Set **Origin Type** to **Storage Zone**, select the zone you created, and click **Add Pull Zone**.
>
> Your site is live at `https://<pull-zone-name>.b-cdn.net`.

## Site configuration

When you deploy with the Bunny CLI and detection doesn't fit your project, add a `sites` block to `bunny.jsonc` at your project root. Every field is optional:

```jsonc bunny.jsonc theme={null}
{
  "sites": {
    "name": "my-site",
    "build": "npm run build",
    "dir": "dist",
    "spa": true
  }
}
```

| Field | Description |
| - | - |
| `name` | The site this directory deploys to |
| `build` | The command `bunny sites deploy --build` runs |
| `dir` | The directory to deploy, relative to `bunny.jsonc` |
| `spa` | Serve `index.html` for unknown paths, for apps with client-side routing |

`bunny sites ci init` reads the same file, so GitHub Actions builds and deploys what you deploy locally.

## Framework guides

Each guide lists the build command and output directory, any config your framework needs for static output, and the steps for both the CLI and a manual deploy.

### JavaScript frameworks

> [card] [Analog](https://bunny.net/docs/storage/static-site-hosting/analog.md)

> [card] [Angular](https://bunny.net/docs/storage/static-site-hosting/angular.md)

> [card] [Astro](https://bunny.net/docs/storage/static-site-hosting/astro.md)

> [card] [Brunch](https://bunny.net/docs/storage/static-site-hosting/brunch.md)

> [card] [Ember](https://bunny.net/docs/storage/static-site-hosting/ember.md)

> [card] [Next.js](https://bunny.net/docs/storage/static-site-hosting/nextjs.md)

> [card] [Nuxt](https://bunny.net/docs/storage/static-site-hosting/nuxt.md)

> [card] [Preact](https://bunny.net/docs/storage/static-site-hosting/preact.md)

> [card] [Qwik](https://bunny.net/docs/storage/static-site-hosting/qwik.md)

> [card] [React](https://bunny.net/docs/storage/static-site-hosting/react.md)

> [card] [React Router](https://bunny.net/docs/storage/static-site-hosting/react-router.md)

> [card] [SolidStart](https://bunny.net/docs/storage/static-site-hosting/solidstart.md)

> [card] [SvelteKit](https://bunny.net/docs/storage/static-site-hosting/sveltekit.md)

> [card] [Vite](https://bunny.net/docs/storage/static-site-hosting/vite.md)

> [card] [Vue](https://bunny.net/docs/storage/static-site-hosting/vue.md)

### Static site generators

> [card] [Elder.js](https://bunny.net/docs/storage/static-site-hosting/elderjs.md)

> [card] [Eleventy](https://bunny.net/docs/storage/static-site-hosting/eleventy.md)

> [card] [Gatsby](https://bunny.net/docs/storage/static-site-hosting/gatsby.md)

> [card] [Gridsome](https://bunny.net/docs/storage/static-site-hosting/gridsome.md)

> [card] [Hexo](https://bunny.net/docs/storage/static-site-hosting/hexo.md)

> [card] [Hugo](https://bunny.net/docs/storage/static-site-hosting/hugo.md)

> [card] [Jekyll](https://bunny.net/docs/storage/static-site-hosting/jekyll.md)

> [card] [Pelican](https://bunny.net/docs/storage/static-site-hosting/pelican.md)

> [card] [Zola](https://bunny.net/docs/storage/static-site-hosting/zola.md)

### Documentation

> [card] [Docusaurus](https://bunny.net/docs/storage/static-site-hosting/docusaurus.md)

> [card] [MkDocs](https://bunny.net/docs/storage/static-site-hosting/mkdocs.md)

> [card] [Sphinx](https://bunny.net/docs/storage/static-site-hosting/sphinx.md)

> [card] [VitePress](https://bunny.net/docs/storage/static-site-hosting/vitepress.md)

### Other

> [card] [Blazor WebAssembly](https://bunny.net/docs/storage/static-site-hosting/blazor.md)

> [card] [Static HTML](https://bunny.net/docs/storage/static-site-hosting/static-html.md)

## Single-page apps

Single-page apps (React, Vue, Angular, and others) handle routing in the browser. When someone opens a deep link such as `/dashboard` or refreshes the page, the request has to return `index.html` so the router can take over.

The Bunny CLI sets this up for frameworks that build single-page apps, and asks when a build looks like one. For a manual deploy, configure your storage zone:

**1. Open your storage zone**

In the [bunny.net dashboard](https://dash.bunny.net), go to **Storage** and select your storage zone.

**2. Open Error handling**

Open the **Error handling** page.

**3. Serve index.html for missing paths**

Enter `/index.html` in the **404 File path** field, check **Rewrite 404 to 200 status code**, and click **Save**.

Requests for missing files with an extension, such as `.js`, `.css`, or images, still return a 404. See [Storage zone settings](https://bunny.net/docs/storage/settings.md#error-handling) for details.

## Add a custom domain

With the Bunny CLI, add the domain to your site:

```bash theme={null}
bunny sites domains add example.com
```

The CLI prints the `CNAME` record to create with your DNS provider. Once the record resolves, issue a free certificate with `bunny sites domains ssl example.com`.

For a manual deploy, add the hostname to your pull zone by following [Custom hostnames](https://bunny.net/docs/cdn/custom-hostname.md).

## Resize images with Bunny Optimizer

[Bunny Optimizer](https://bunny.net/docs/optimizer/dynamic-images/overview.md) resizes images at the edge from query parameters such as `?width=640`, so your build can ship one copy of each image.

`bunny sites create` leaves query strings and Optimizer off, so open the site's pull zone under **CDN → Pull Zones**:

* Turn on [URL Query String](https://bunny.net/docs/cdn/vary-cache.md#url-query-string) vary, so each `?width=` gets its own cache entry.
* Enable [Bunny Optimizer](https://bunny.net/docs/optimizer/quickstart.md), then turn on the Dynamic Image API and automatic WebP under **Optimizer → Settings**. Your build has already minified CSS and JavaScript, so turn Optimizer's minification off.

The [Next.js](https://bunny.net/docs/storage/static-site-hosting/nextjs.md#resize-images-with-bunny-optimizer), [Nuxt](https://bunny.net/docs/storage/static-site-hosting/nuxt.md#resize-images-with-bunny-optimizer), [Astro](https://bunny.net/docs/storage/static-site-hosting/astro.md#resize-images-with-bunny-optimizer), and [Angular](https://bunny.net/docs/storage/static-site-hosting/angular.md#resize-images-with-bunny-optimizer) guides plug Optimizer into each framework's image component. Anywhere else, write the `srcset` yourself:

```html theme={null}
<img
  src="/images/photo.jpg?width=1200"
  sizes="100vw"
  alt="Photo"
/>
```

## Cache configuration

Static frontends benefit from long cache times on assets. Consider these settings in your pull zone:

| File type | Recommended cache time |
| - | - |
| HTML | Short (1 hour) or use cache busting |
| JS/CSS (hashed) | Long (1 year) |
| Images | Long (1 month+) |
| Fonts | Long (1 year) |

> [!NOTE]
>
> Build tools such as Vite add content hashes to filenames (for example,
> `main.a1b2c3.js`), so these files are safe to cache indefinitely.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.