env

The env object holds the bindings of a worker. It is the second argument of the fetch() handler, and it is exactly { KV, FS }: env.KV opens key–value storage, and env.FS returns the assets that you declare with worker:fs.

There are no other bindings. A worker has no environment variables or secrets, no Durable Objects, R2, D1 or Queues bindings, and no service bindings, AI, Vectorize, Analytics Engine, Hyperdrive, Browser Rendering, send_email or rate-limit bindings. Cron triggers do not exist either, and import { env } from 'cloudflare:workers' is not allowed.

Instance properties

env.KV

The key–value storage of the worker. It has exactly one member, open(), which returns a KVNamespace. There is no get or put directly on env.KV.

env.FS

An object of worker-only assets, keyed by the exact worker:fs name, with no leading slash. Without any worker:fs element it is an empty object. Each entry has these properties:

headers

An array of [name, value] pairs, taken in order from the h:* attributes of the element.

type

A string, or undefined: the media type of the asset. It comes from o:type; else from the extension of the key (worker:fs=json gets application/json); else from the type of a data: URL; else it is application/octet-stream for binary content. An unknown text extension leaves it undefined. No charset is appended.

body

A string: the content. For binary assets it is the base64 text of the bytes.

bodyEncoding and bodyBytes

Present only for binary assets: the string 'base64' and the decoded length in bytes.

response Experimental

A getter that builds a new Response every time you read it: the body is decoded from base64 when needed, and the headers are the h:* pairs, then content-type when type is set, then content-length when bodyBytes is set. It exists in the playground and in the current shell of RTEdge.net. Deployments that were built with an older shell may lack it, and redeploying fixes that.

Note: response is experimental and may change. Build the Response yourself if you need your code to be stable.

The content of an entry is read from a copy of the element without its RTCode attributes. If o:content is set, its value names the property to read, such as innerHTML. Otherwise <style> and <script> use textContent, <template> uses innerHTML, an <img src=data:…> becomes decoded bytes, and anything else uses outerHTML. When several elements share a name, their text parts are joined with a newline, and the first element's type and headers win. A binary asset that shares its name with any other entry is an error (Duplicate binary worker:fs asset), so never reuse the name of a binary asset.

worker:fs alone does not hide an element: it stays in the served page. Add edge:remove or edge:redact to keep it out of the HTML; the worker still gets its content. Both only change the served page, and a public source opened with ? still shows the element.

Note: env.FS is embedded in the worker script, so it counts toward the size of your deployment. The same object serves every request of an isolate, so treat it as read-only. In the playground it refreshes only on a full output load; use reload on the element while you edit.

With assets present, FS is a non-enumerable getter. Object.keys(env) then returns only ['KV'], and { ...env } drops FS. Read env.FS, or destructure { FS } directly. Without assets, FS is an empty object and both keys show.

At the edge, worker:fs elements inside <template> content are collected, and edge:remove and edge:redact apply to their descendants. The playground does neither. env.FS exists only in shells from 2025-09-29: redeploy older deployments to get it.

Instance methods

env.KV.open()

Opens a scoped namespace. It returns a KVNamespace at once; do not await it, because the namespace answers every property, including then, and an awaited namespace never settles.

js
env.KV.open()
env.KV.open(scope)
env.KV.open(scope, depth)
scope Optional

An object with any of the keys user, domain and route, written in that order. The default is {}. A key outside this list throws Error: Invalid keys: …, and a wrong order throws Error: Invalid key order: …; expected order: user, domain, route. When route is present, domain is ignored and deleted from the object you passed. A falsy user counts as absent and opens a scope shared by all visitors. See the six scopes.

depth Optional Experimental

An integer, 0 or negative. -n lifts the last n scope values out of the stored prefix, so you write them into the key yourself, joined with ● (U+25CF), and list() names include them. A positive depth acts as 0, and a depth beyond the number of scope values throws a RangeError. The default is 0.

Note: depth is experimental and may change.

Return value: a KVNamespace.

Examples

Serving a worker-only file

The JSON stays in the page source of the playground, but edge:remove keeps it out of the deployed page. The worker reads it from env.FS and answers with its stored type.

html
<output id=out></output>
<script type=module>
  out.value = await fetch(':data').then(r => r.text())
</script>
<script worker:fs=data.json type=application/json edge:remove reload>{ "ok": true }</script>
<script type=worker edge>
  export default {
    fetch: (request, { FS }) => new Response(FS['data.json'].body, { headers: { 'content-type': FS['data.json'].type } })
  }
</script>

What env contains

Without worker:fs elements, env has the keys KV and FS, and env.KV has the single member open.

html
<output id=shape></output>
<script type=module>
  shape.value = await fetch(':env').then(r => r.text())
</script>
<script type=worker edge>
  export default {
    fetch: (request, env) => Response.json({ env: Object.keys(env), KV: Object.keys(env.KV) })
  }
</script>

You should see {"env":["KV","FS"],"KV":["open"]}. Add a worker:fs asset and FS disappears from the first list, because it becomes a non-enumerable getter.

Specifications

Not part of any specification. env follows the shape of the Cloudflare Workers fetch() handler, with the bindings that RTCode.io and RTEdge.net provide.

Availability

FeaturePlaygroundRTEdge.netNotes
env.KV.open()YesYesPlayground data lives in your browser; a value plus its metadata may be up to 64 KiB there and 10 MiB on RTEdge.net.
env.FSYesYesNeeds shell 2025-09-29 or later on RTEdge.net. Templates and edge:remove are handled at the edge only.
env.FS[name].responseYesPartialExperimental. Builds deployed with an older shell may lack it.
depth argumentYesYesExperimental.
Environment variables and secretsNoNoThere are no other bindings.

See also