---
title: Static assets
description: "Serve files from the edge, with your handler owning only the paths it wants."
---

## Configuration

```jsonc
"assets": {
  "directory": "public",
  "binding": "ASSETS",
  "not_found_handling": "single-page-application",
  "run_sprout_first": ["/api/*"]
}
```

## How requests are routed

The edge serves matching files directly. Your handler only sees the paths listed in `run_sprout_first` and requests that match no file. It can call `env.ASSETS.fetch(request)` to serve a file itself, for example behind an auth check. Binary files come back unchanged.

```js
fetch(request) {
  const url = new URL(request.url);
  if (url.pathname.startsWith("/api/")) return handleApi(request);
  return env.ASSETS.fetch(request);
}
```

## Options

| Field | Values | Behavior |
| --- | --- | --- |
| `not_found_handling` | `"none"` | `env.ASSETS.fetch` answers an unknown path with a plain 404. |
| | `"single-page-application"` | It answers unknown paths with `index.html` and a 200. |
| | `"404-page"` | It answers unknown paths with `/404.html` and a 404. |
| `run_sprout_first` | `true` | Every request goes to the handler first. |
| | `string[]` (globs) | Only matching paths go to the handler first. Usually what you want, for example `["/api/*"]`. |

:::tip
For a static site, use `404-page` and return `env.ASSETS.fetch(request)` from the handler. An SPA fallback on a site with no client-side router turns every typo into a 200.
:::

## Headers and redirects

Put a `_headers` or `_redirects` file at the root of the assets directory, in the Cloudflare Pages format. The deployed edge applies them; `sproutboat dev` and standalone binaries ignore them.

```txt title="public/_redirects"
/old-page   /new-page       301
/blog/:slug /posts/:slug
/docs/*     https://docs.example.com/:splat
```

```txt title="public/_headers"
/*
  X-Frame-Options: DENY
/fonts/*
  Cache-Control: public, max-age=31536000
```

- A redirect is checked before any file and wins even when a file exists at the path. Its status defaults to 302 and must be a 3xx.
- Header rules apply to files the edge serves, in file order. A rule's value replaces the default (for example `Cache-Control`), and `! Name` removes a header.

## Related

- [Platform limits](/docs/platform/limits): asset size limits

On a [standalone binary](/docs/get-started/standalone), assets are compiled in, up to 8 MB in total.
