Skip to content
runlot

Static assets

Every file in the static assets directory is included in the bundle and served from the worker through `env.assets`.

Every file in the directory that assets in runlot.json points to is uploaded with the deploy.

runlot.json
{ "name": "my-app", "main": "src/index.ts", "assets": "public" }

Serving static assets from the worker

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    if (url.pathname.startsWith("/static/")) {
      return env.assets.fetch(
        new Request(new URL(url.pathname.slice("/static".length), url), request),
      );
    }
    return new Response("hello");
  },
};

Paths are resolved relative to the assets directory. In the example above, /static/logo.svg points to the file public/logo.svg.

Asset files are not served ahead of your code automatically. Decide explicitly in your worker code which paths serve assets. That way you avoid collisions between asset paths and application routes such as /about.

Serving files ahead of the worker

Set runWorkerFirst: false and the order reverses: an exact file in the assets directory is served, and every other path goes to your worker.

runlot.json
{ "name": "my-app", "main": "build/server/index.js", "assets": "build/client", "runWorkerFirst": false }

This is what a framework that builds its own worker needs — React Router, Astro, SvelteKit, Nuxt all render and expect the platform to have served their client directory already. See Frameworks.

A path that is not a file still reaches your worker, including one with an extension. The assets directory never answers on your worker's behalf.

Assets-only deploys

If you set assets without main, an entry point that forwards every request to the static assets is generated for you.

runlot.json
{ "name": "my-site", "assets": "dist" }

Writing the same behavior yourself looks like this.

export default {
  fetch(request, env) {
    return env.assets.fetch(request);
  },
};

What cannot go into a bundle

  • Symbolic links. A bundle contains only real files.
  • Anything outside the project root. "assets": "../dist" is rejected.
  • Duplicate entries. A bundle with the same path twice is rejected.

node_modules and build caches inside the assets directory are uploaded too. If your bundle is larger than you expected, check for those files first. The size limits are listed in Bundle rules.

On this page