Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Static assets
description: Host static assets on Cloudflare's global network and deliver faster load times worldwide with Workers for Platforms.
---

import { Aside } from "@astrojs/starlight/components";


Workers for Platforms lets you deploy front-end applications at scale. By hosting static assets on Cloudflare's global network, you can deliver faster load times worldwide and eliminate the need for external infrastructure. You can also combine these static assets with dynamic logic in Cloudflare Workers, providing a full-stack experience for your customers.

Expand Down Expand Up @@ -57,12 +57,11 @@ Before sending any file data, you need to tell Cloudflare which files you intend
- A hash (32-hex characters) representing the file contents
- The file size in bytes

<Aside type="note" title="Asset Isolation Considerations">
:::note[Asset Isolation Considerations]
Static assets uploaded to Workers for Platforms are associated with the namespace rather than with individual User Worker. If multiple User Workers exist under the same namespace, assets with identical hashes may be shared across them. **JWTs should therefore only be shared with trusted platform services and should never be distributed to end-users.**

If strict isolation of assets is required, we recommend either salting with a random value each time, or incorporating an end-user identifier (for example, account ID or Worker script ID) within the hashing process, to ensure uniqueness. For example, `hash = slice(sha256(accountID + fileContents), 32)`.

</Aside>
:::

#### Example manifest (JSON)

Expand Down Expand Up @@ -134,9 +133,8 @@ If the response to the Upload Session API returns `buckets`, that means you have

Use the [Workers Assets Upload API](/api/resources/workers/subresources/assets/subresources/upload/) to transmit the raw file bytes in base64-encoded format for any missing or changed files. Once uploaded, Cloudflare will store these files so they can then be attached to a User Worker.

<Aside type="caution">
Asset uniqueness is determined by the provided hash and are associated globally to their namespace rather than with each specific User Worker. If an asset has already been uploaded for that namespace earlier, Cloudflare will automatically omit sending this asset hash back in the `buckets` response to save you from re-uploading the same thing twice. This means that an asset can be shared between multiple User Workers if it shares the same hash unless you **explicitly make the hash unique**. If you require full isolation between assets across User Workers, incorporate a unique identifier within your asset hashing process (either salting it with something entirely random each time, or by including the end-user account ID or their Worker name to retain per-customer re-use).
</Aside>
**Caution**
Asset uniqueness is determined by the provided hash and are associated globally to their namespace rather than with each specific User Worker. If an asset has already been uploaded for that namespace earlier, Cloudflare will automatically omit sending this asset hash back in the `buckets` response to save you from re-uploading the same thing twice. This means that an asset can be shared between multiple User Workers if it shares the same hash unless you **explicitly make the hash unique**. If you require full isolation between assets across User Workers, incorporate a unique identifier within your asset hashing process (either salting it with something entirely random each time, or by including the end-user account ID or their Worker name to retain per-customer re-use).

#### API Request Authentication

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ head: []
description: Configuring environment variables and secrets for local development
---

import { Aside, PackageManagers, Steps } from "~/components";
import { PackageManagers, Steps } from "~/components";

During local development, you may need to configure **environment variables** (such as API URLs, feature flags) and **secrets** (API tokens, private keys). You can use a `.dev.vars` file in the root of your project to override environment variables for local development, and both [Wrangler](/workers/configuration/environment-variables/#compare-secrets-and-environment-variables) and the [Vite plugin](/workers/vite-plugin/reference/secrets/) will respect this override.

<Aside type="caution">
Be sure to add `.dev.vars` to your `.gitignore` so it never gets committed.
</Aside>
:::caution
Be sure to add `.dev.vars` to your `.gitignore` so it never gets committed.
:::

### Why use a `.dev.vars` file?

Expand Down
21 changes: 7 additions & 14 deletions src/content/docs/workers/development-testing/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
Render,
PackageManagers,
WranglerConfig,
Aside,
InlineBadge,
CardGrid,
Card,
Expand Down Expand Up @@ -266,13 +265,11 @@ To connect to a high-fidelity version of the Images API, and verify that all tra

</WranglerConfig>

<Aside type="note">

:::note
If `experimental_remote: true` is not specified for Browser Rendering, Vectorize, mTLS, or Images, Cloudflare **will issue a warning**. This prompts you to consider enabling it for a more production-like testing experience.

If a Workers AI binding has `experimental_remote` set to `false`, Cloudflare will **produce an error**. If the property is omitted, Cloudflare will connect to the remote resource and issue a warning to add the property to configuration.

</Aside>
:::

#### [Dispatch Namespaces](/cloudflare-for-platforms/workers-for-platforms/get-started/developing-with-wrangler/):

Expand Down Expand Up @@ -319,11 +316,9 @@ If `experimental_remote: true` is specified in Wrangler configuration for any of
- [**Hyperdrive**](/workers/wrangler/configuration/#hyperdrive): This is being actively worked on, but is currently unsupported.
- [**Rate Limiting**](/workers/runtime-apis/bindings/rate-limit/#configuration): Local development sessions typically should not share or affect rate limits of your deployed Workers. Rate limiting logic should be tested against local simulations.

<Aside type="tip">

:::note
If you have use-cases for connecting to any of the remote resources above, please [open a feature request](https://github.com/cloudflare/workers-sdk/issues) in our [`workers-sdk` repository](https://github.com/cloudflare/workers-sdk).

</Aside>
:::

### Important Considerations

Expand Down Expand Up @@ -361,11 +356,9 @@ are however not directly compatible with `experimental_startRemoteProxySession`.
pass them to `experimental_startRemoteProxySession`, so for this wrangler exposes `unstable_convertConfigBindingsToStartWorkerBindings` which is a simple utility to convert
the bindings in an `Unstable_Config` object into a structure that can be passed to `experimental_startRemoteProxySession`.

<Aside type="note">
This type conversion is temporary. In the future, the types will be unified so
you can pass the config object directly to
`experimental_startRemoteProxySession`.
</Aside>
:::note
This type conversion is temporary. In the future, the types will be unified so you can pass the config object directly to `experimental_startRemoteProxySession`.
:::

#### `experimental_maybeStartOrUpdateRemoteProxySession`

Expand Down
7 changes: 2 additions & 5 deletions src/content/docs/workers/development-testing/local-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
Render,
PackageManagers,
FileTree,
Aside,
} from "~/components";

Whether you are using Wrangler or the [Cloudflare Vite plugin](https://developers.cloudflare.com/workers/vite-plugin/), your workflow for **accessing** data during local development remains the same. However, you can only [populate local resources with data](/workers/development-testing/local-data/#populating-local-resources-with-data) via the Wrangler CLI.
Expand All @@ -28,11 +27,9 @@ When you first start developing, your local resources will be empty. You'll need

### KV namespaces

<Aside type="caution" title="Syntax note">

:::caution[Syntax note]
Since version 3.60.0, Wrangler supports the `kv ...` syntax. If you are using versions below 3.60.0, the command follows the `kv:...` syntax. Learn more in the [Wrangler commands for KV page](/kv/reference/kv-commands/).

</Aside>
:::

#### [Add a single key-value pair](/workers/wrangler/commands/#kv-key)

Expand Down
17 changes: 6 additions & 11 deletions src/content/docs/workers/development-testing/multi-workers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ head: []
description: Learn how to develop with multiple Workers using different approaches and configurations.
---

import { Aside, PackageManagers, Steps, WranglerConfig } from "~/components";
import { PackageManagers, Steps, WranglerConfig } from "~/components";

When building complex applications, you may want to run multiple Workers during development. This guide covers the different approaches for running multiple Workers locally and when to use each approach.

## Single dev command

<Aside type="tip">

:::note
We recommend this approach as the default for most development workflows as it ensures the best compatibility with bindings.

</Aside>
:::

You can run multiple Workers in a single dev command by passing multiple configuration files to your dev server:

Expand Down Expand Up @@ -83,12 +81,9 @@ You can also run each Worker in a separate dev commands, each with its own termi

These Workers run in different dev commands but can still communicate with each other via service bindings or tail consumers **regardless of whether they are started with `wrangler dev` or `vite dev`**.

<Aside type="note">

You can also combine both approaches — for example, run a group of Workers together through `vite dev` using `auxiliaryWorkers`, while running another Worker separately with `wrangler dev`. This allows you to keep tightly coupled Workers running under a single dev command, while keeping independent or shared Workers in separate ones. However,
running `wrangler dev` with multiple configuration files (e.g. `wrangler dev -c ./app/wrangler.jsonc -c ./api/wrangler.jsonc`) does **not** support cross-process bindings at the moment.

</Aside>
:::note
You can also combine both approaches — for example, run a group of Workers together through `vite dev` using `auxiliaryWorkers`, while running another Worker separately with `wrangler dev`. This allows you to keep tightly coupled Workers running under a single dev command, while keeping independent or shared Workers in separate ones. However, running `wrangler dev` with multiple configuration files (e.g. `wrangler dev -c ./app/wrangler.jsonc -c ./api/wrangler.jsonc`) does **not** support cross-process bindings at the moment.
:::

**Use this approach when:**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar:
order: 2
---

import { WranglerConfig, Aside, TypeScriptExample, Render } from "~/components";
import { WranglerConfig, TypeScriptExample, Render } from "~/components";

Single Page Applications (SPAs) are web applications which are client-side rendered (CSR). They are often built with a framework such as [React](/workers/framework-guides/web-apps/react/), [Vue](/workers/framework-guides/web-apps/vue/) or [Svelte](/workers/framework-guides/web-apps/svelte/). The build process of these frameworks will produce a single `/index.html` file and accompanying client-side resources (e.g. JavaScript bundles, CSS stylesheets, images, fonts, etc.). Typically, data is fetched by the client from an API with client-side requests.

Expand Down Expand Up @@ -39,12 +39,11 @@ Configuring `assets.not_found_handling` to `single-page-application` overrides t

For more explicit control over SPA routing behavior, you can use `run_worker_first` with an array of route patterns. This approach disables the automatic `Sec-Fetch-Mode: navigate` detection and gives you explicit control over which requests should be handled by your Worker script vs served as static assets.

<Aside type="note">
Advanced routing control is supported in:
- [Wrangler](/workers/wrangler/install-and-update/) v4.20.0 and above
- [Cloudflare Vite plugin](/workers/vite-plugin/get-started/) v1.7.0 and above

</Aside>
:::note
Advanced routing control is supported in:
- [Wrangler](/workers/wrangler/install-and-update/) v4.20.0 and above
- [Cloudflare Vite plugin](/workers/vite-plugin/get-started/) v1.7.0 and above
:::

<WranglerConfig>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar:
order: 4
---

import { WranglerConfig, TypeScriptExample, Aside } from "~/components";
import { WranglerConfig, TypeScriptExample } from "~/components";

If you have both static assets and a Worker script configured, Cloudflare will first attempt to serve static assets if one matches the incoming request. You can read more about how we match assets in the [HTML handling docs](/workers/static-assets/routing/advanced/html-handling/).

Expand All @@ -18,14 +18,9 @@ This allows you to easily combine together these two features to create powerful

You can configure the [`assets.run_worker_first` setting](/workers/static-assets/binding/#run_worker_first) to control when your Worker script runs relative to static asset serving. This gives you more control over exactly how and when those assets are served and can be used to implement "middleware" for requests.

<Aside type="caution">
If you are using [Smart Placement](/workers/configuration/smart-placement/) in
combination with `assets.run_worker_first`, you may find that placement
decisions are not optimized correctly as, currently, the entire Worker script
is placed as a single unit. This may not accurately reflect the desired
"split" in behavior of edge-first vs. smart-placed compute for your
application. This is a limitation that we are currently working to resolve.
</Aside>
:::caution
If you are using [Smart Placement](/workers/configuration/smart-placement/) in combination with `assets.run_worker_first`, you may find that placement decisions are not optimized correctly as, currently, the entire Worker script is placed as a single unit. This may not accurately reflect the desired "split" in behavior of edge-first vs. smart-placed compute for your application. This is a limitation that we are currently working to resolve.
:::

### Run Worker before each request

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{}
---

import { Aside } from "~/components";

<Aside> You cannot use the same license key twice, or reuse a key once the virtual machine has been registered with Cloudflare. You need a new key from your account team for every new Virtual Connector.</Aside>

:::note
You cannot use the same license key twice, or reuse a key once the virtual machine has been registered with Cloudflare. You need a new key from your account team for every new Virtual Connector.
:::
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ params:
- url
---

import { Aside, Markdown } from "~/components";

<Aside title="VLAN tagging">
import { Markdown } from "~/components";

:::note[VLAN tagging]
Virtual Connector supports creating subinterfaces through the use of [802.1Q VLAN tagging](https://en.wikipedia.org/wiki/IEEE_802.1Q).

Use VLAN ID <code>0</code> when:
Expand All @@ -17,5 +16,4 @@ Use VLAN ID <code>0</code> when:
You can also configure subinterfaces on the Virtual Connector by associating the network interface with a Port Group or Distributed Port Group trunk and specifying a VLAN ID in addition to the port associated with the network interface (VLAN ID <code>1</code>-<code>4094</code>).

Refer to <Markdown text={props.url} /> for more information.

</Aside>
:::
10 changes: 5 additions & 5 deletions src/content/partials/workers/navigation_requests.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
{}
---

import { Aside, TypeScriptExample } from "~/components";
import { TypeScriptExample } from "~/components";

### Navigation requests

If you have a Worker script (`main`), have configured `assets.not_found_handling`, and use the [`assets_navigation_prefers_asset_serving` compatibility flag](/workers/configuration/compatibility-flags/#navigation-requests-prefer-asset-serving) (or set a compatibility date of `2025-04-01` or greater), _navigation requests_ will not invoke the Worker script. A _navigation request_ is a request made with the `Sec-Fetch-Mode: navigate` header, which browsers automatically attach when navigating to a page. This reduces billable invocations of your Worker script, and is particularly useful for client-heavy applications which would otherwise invoke your Worker script very frequently and unnecessarily.

<Aside type="note">
:::note
This can lead to surprising but intentional behavior. For example, if you define an API endpoint in a Worker script (e.g. `/api/date`) and then fetch it with a client-side request in your SPA (e.g. `fetch("/api/date")`), the Worker script will be invoked and your API response will be returned as expected. However, if you navigate to `/api/date` in your browser, you will be served an HTML file. Again, this is to reduce the number of billable invocations for your application while still maintaining SPA-like functionality. This behavior can be disabled by setting the [`assets_navigation_has_no_effect` compatibility flag](/workers/configuration/compatibility-flags/#navigation-requests-prefer-asset-serving).
</Aside>
:::

<Aside type="tip">
:::note
If you wish to run the Worker script ahead of serving static assets (e.g. to log requests, or perform some authentication checks), you can additionally configure the [`assets.run_worker_first` setting](/workers/static-assets/routing/worker-script/#run_worker_first). This will retain your `assets.not_found_handling` behavior when no other asset matches, while still allowing you to control access to your application with your Worker script.
</Aside>
:::

#### Client-side callbacks

Expand Down