---
title: "Static assets"
---

> Documentation Index
> Fetch the complete documentation index at: https://ermahgerd-docs.t-bd7662a5eeb4.workers.ermahgerd.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Static assets

Deploy a static site or attach files to a Worker with ordinary Wrangler
configuration. Asset bytes use the platform's existing storage blob engine;
the assets service adds immutable manifests, upload validation, routing,
retention, and serving. This is not an S3 bucket, a pull-through cache, or a CDN
product, and it does not create a process per site.

```toml
[assets]
directory = "./public"
binding = "ASSETS"
run_worker_first = ["/api/*"]
```

Then run `npx wrangler deploy` after [connecting Wrangler](/build/connect-wrangler/). A site with no Worker script
can omit `main`; a full-stack Worker can use `env.ASSETS.fetch(request)`.
See [Databases](/build/databases/) for the combined native example and runnable check.

## Routing

Matching files are served first by default. Requests without an asset match
fall through to the Worker. Set `run_worker_first = true` to invoke the Worker
first, or use a list of path patterns and `!` exclusions to protect selected
paths. These patterns support one wildcard per pattern.

Supported asset behavior includes GET and HEAD, content types, ETags and
If-None-Match, byte ranges, ETag-based If-Range, HTML handling modes, SPA index
fallback, and nearest-parent `404.html` fallback. `_headers` path rules and
`_redirects` path/placeholder rules are validated during publication. Redirect
statuses 301/302/303/307/308 and local 200 rewrites are supported. External proxy
rewrites and hostname-based `_headers` rules are rejected. Date-based conditional
requests are not implemented; use ETags.
Named placeholders occupy a complete path segment (for example, `/blog/:slug`);
ambiguous adjacent captures are rejected before publication.

An asset hit currently passes through a platform-injected wrapper in the same
dynamic isolate as the Worker. It does not invoke the application's fetch
handler on an assets-first hit, but it is **not** a separate isolate-free CDN
fast path. Application module initialization can therefore affect first use.

## Publication and rollback

Wrangler submits a manifest, receives an expiring organization/Worker-scoped
upload capability, and uploads only missing hashes. The pinned CLI's single
asset upload protocol is supported. The service checks both byte length and
Wrangler's BLAKE3 content hash, and refuses to publish an incomplete manifest.

Each Worker version records one immutable asset manifest. Code, bindings, and
manifest change together at the existing routing cutover; rollback selects the
old version's manifest too. Requests already executing retain their selected
version. The console's deployment details show file count and manifest bytes.

Retained Worker versions pin their assets. After pruning, manifests and blobs
remain available for the HAProxy drain budget (one hour by default), so an
in-flight old isolate can still fetch its files. This grace retention remains
charged to the organization. Abandoned uploads expire after one
hour. The assets service periodically collects expired, unreferenced sessions
and blobs. A durable control-plane cleanup outbox makes publication/pruning
cleanup retryable after restart or service failure; cleanup failure does not
turn a successful deployment into a reported failure.

Retention is not stale-URL routing: after a new deployment, new requests resolve
against the newly active manifest. A browser holding old HTML may request an
old fingerprinted URL that is absent from the new manifest and receive a 404.
Include old fingerprinted files in subsequent builds when that overlap is
needed. The service does not search another version's manifest behind your back.

## Isolation and quotas

Assets are scoped by organization and Worker version. Stored blobs use a private
namespace outside tenant-visible R2 buckets. Tenants cannot list them using S3
or R2 bindings. Identical hashes deduplicate within an organization, not across
organizations. Service credentials remain in trusted runtime bindings.

Asset allowances follow the organization tier: Free permits **64 MiB** and two
pending uploads, Standard permits **512 MiB** and five, and Enterprise permits
**2 GiB** and ten. Each manifest supports up to 20,000 files and each file up
to 25 MiB. Assets do not also consume the organization's R2 bucket allowance.
Expired upload slots are reclaimed by the periodic collector; referenced
versions remain charged until their blobs are no longer retained.

## Investigate delivery

Review the Worker's deployment details for its asset manifest and
[Observability](/build/observability/) for HTTP outcomes. Missing files,
conditional responses, and redirects have different meanings from service
failures. Compare a reported file with the active version's manifest before
assuming storage loss.

Operators use [Platform observability](/operations/observability/) for delivery and
upload signals and [Runtime isolation](/operations/runtime-isolation/#capability-checks)
for continuity checks across code and manifest changes.

Source: https://ermahgerd-docs.t-bd7662a5eeb4.workers.ermahgerd.io/build/static-assets/index.mdx
