> ## 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://.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} 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.