Skip to main content
Bindings are how workers access external resources and configuration. Each binding gives the worker a JavaScript API object that provides access to a specific capability. This capability-based approach makes it clear what each worker can access and prevents SSRF attacks.

How bindings work

Bindings appear differently depending on your worker syntax:
  • ES modules: Bindings are properties on the env object passed to handlers
  • Service workers: Bindings are global variables
// ES modules syntax
export default {
  async fetch(request, env, ctx) {
    // Access bindings via env object
    const apiKey = env.API_KEY;
    const response = await env.backend.fetch(request);
    return response;
  }
};

// Service worker syntax
addEventListener('fetch', event => {
  // Access bindings as globals
  const apiKey = API_KEY;
  const response = await backend.fetch(request);
  event.respondWith(response);
});

Defining bindings

Bindings are defined in the bindings list of your worker configuration:
const myWorker :Workerd.Worker = (
  modules = [
    (name = "index.js", esModule = embed "index.js"),
  ],
  compatibilityDate = "2023-02-28",

  bindings = [
    (name = "API_KEY", text = "secret-value"),
    (name = "backend", service = "backend-api"),
    (name = "DATABASE", durableObjectNamespace = "Counter"),
  ],
);

Binding types

Simple data bindings

These bindings provide static data to your worker:
text
Text
A string value.
(name = "API_KEY", text = "my-secret-key"),
(name = "ENVIRONMENT", text = "production"),
const apiKey = env.API_KEY;  // "my-secret-key"
data
Data
Binary data as an ArrayBuffer.
(name = "SECRET_BYTES", data = embed "secret.bin"),
const bytes = env.SECRET_BYTES;  // ArrayBuffer
json
Text
JSON data, parsed into a JavaScript object.
(name = "CONFIG", json = embed "config.json"),
(name = "SETTINGS", json = "{\"debug\":true}"),
const config = env.CONFIG;  // Parsed object
console.log(config.debug);  // true
wasmModule
Data
WebAssembly module instance. Only supported in service workers syntax.
Deprecated. Use ES modules syntax and embed Wasm modules as modules instead.
(name = "WASM", wasmModule = embed "module.wasm"),

Cryptographic key binding

cryptoKey
CryptoKey
A CryptoKey instance for WebCrypto API operations. You can prevent the worker from extracting raw key material by setting extractable = false.
(name = "SIGNING_KEY", cryptoKey = (
  raw = embed "key.bin",
  algorithm = (name = "HMAC"),
  extractable = false,
  usages = ["sign", "verify"],
)),
Key formats:
  • raw: Raw key material
  • hex: Hex-encoded key
  • base64: Base64-encoded key
  • pkcs8: Private key in PEM-encoded PKCS#8
  • spki: Public key in PEM-encoded SPKI
  • jwk: Key in JSON format
Algorithm:
  • name: Just a name like "AES-GCM"
  • json: Object encoded as JSON
Usage values: encrypt, decrypt, sign, verify, deriveKey, deriveBits, wrapKey, unwrapKey
const signature = await crypto.subtle.sign(
  { name: 'HMAC' },
  env.SIGNING_KEY,
  data
);

Service bindings

service
ServiceDesignator
Binding to a named service (worker, external server, or network).
(name = "backend", service = "backend-api"),
(name = "admin", service = (name = "api-worker", entrypoint = "admin")),
// Call another worker
const response = await env.backend.fetch(request);

// Call with custom request
const response = await env.backend.fetch('https://api.example.com/data');

Durable Object bindings

durableObjectNamespace
DurableObjectNamespaceDesignator
Binding to a Durable Object namespace. In the common case of a class in the same worker, you can specify just the class name as a string.
(name = "COUNTER", durableObjectNamespace = "Counter"),
(name = "ROOMS", durableObjectNamespace = (className = "ChatRoom")),
// Get an object ID
const id = env.COUNTER.idFromName("global");

// Get the object stub
const counter = env.COUNTER.get(id);

// Call methods
const response = await counter.fetch(request);
durableObjectClass
ServiceDesignator
A Durable Object class binding without a storage namespace. Used to implement facets.
(name = "FACET", durableObjectClass = "MyFacet"),

Storage bindings

kvNamespace
ServiceDesignator
KV namespace binding. Requests are converted to HTTP requests targeting the service.
(name = "KV", kvNamespace = "kv-service"),
// KV operations
await env.KV.put("key", "value");
const value = await env.KV.get("key");
await env.KV.delete("key");
r2Bucket
ServiceDesignator
R2 bucket binding for object storage.
(name = "BUCKET", r2Bucket = "r2-service"),
// R2 operations
await env.BUCKET.put("file.txt", "content");
const object = await env.BUCKET.get("file.txt");
await env.BUCKET.delete("file.txt");
r2Admin
ServiceDesignator
R2 admin API binding for bucket management.
(name = "R2_ADMIN", r2Admin = "r2-admin-service"),

Queue binding

queue
ServiceDesignator
Queue binding for message queuing.
(name = "QUEUE", queue = "queue-service"),
// Send messages
await env.QUEUE.send({ data: "message" });
await env.QUEUE.sendBatch([{ body: "msg1" }, { body: "msg2" }]);

Analytics Engine binding

analyticsEngine
ServiceDesignator
Analytics Engine binding for storing analytics events. Requires --experimental flag.
(name = "ANALYTICS", analyticsEngine = "analytics-service"),
env.ANALYTICS.writeDataPoint({
  indexes: ['user:123'],
  doubles: [response_time],
  blobs: ['GET /api'],
});

Hyperdrive binding

hyperdrive
group
Hyperdrive binding for PostgreSQL connection pooling and caching.
(name = "DB", hyperdrive = (
  designator = "hyperdrive-service",
  database = "mydb",
  user = "dbuser",
  password = "dbpass",
  scheme = "postgres",
)),
// Use with postgres client
const client = new Client({ connectionString: env.DB.connectionString });
await client.connect();

Memory cache binding

memoryCache
group
In-memory cache shared across isolates in the same process.
(name = "CACHE", memoryCache = (
  id = "shared-cache",
  limits = (
    maxKeys = 1000,
    maxValueSize = 1048576,  # 1 MiB
    maxTotalValueSize = 10485760,  # 10 MiB
  ),
)),
// Cache operations (simplified API)
await env.CACHE.put("key", value);
const value = await env.CACHE.get("key");

Advanced bindings

fromEnvironment
Text
Takes the value from a system environment variable. The binding value is null if the environment variable isn’t set.
(name = "NODE_ENV", fromEnvironment = "NODE_ENV"),
const nodeEnv = env.NODE_ENV;  // Value from $NODE_ENV
wrapped
WrappedBinding
Wraps a collection of inner bindings in a common API wrapper. The wrapper is an internal module that exports a function accepting the inner bindings.
(name = "shop", wrapped = (
  moduleName = "burrito-shop:binding",
  entrypoint = "default",
  innerBindings = [
    (name = "recipes", json = embed "recipes.json"),
  ],
)),
The wrapper module exports a function:
export default function(env) {
  // env contains innerBindings
  return {
    // Return API object
  };
}
workerLoader
group
Binding for dynamically loading workers at runtime. Workers are cached by name.
(name = "LOADER", workerLoader = (
  id = "worker-cache",  # Optional: share cache across bindings
)),
// Load and execute worker
const worker = await env.LOADER.load("worker-name", workerCode);
const response = await worker.fetch(request);
unsafeEval
Void
Enables access to the UnsafeEval API for dynamic code evaluation.
Use with extreme caution. Dynamic code evaluation can introduce security vulnerabilities.
(name = "UNSAFE_EVAL", unsafeEval = void),
workerdDebugPort
Void
Provides a connect() method to dynamically connect to any workerd instance’s debug port. For local development and testing only.
(name = "DEBUG_PORT", workerdDebugPort = void),
const client = await env.DEBUG_PORT.connect("localhost:1234");
const fetcher = await client.getEntrypoint("service", "entrypoint");

Parameter bindings

Parameter bindings declare that a worker requires a binding but doesn’t specify its value. Another worker can inherit this worker and fill in the binding.
const baseWorker :Workerd.Worker = (
  modules = [(name = "index.js", esModule = embed "index.js")],
  compatibilityDate = "2023-02-28",
  bindings = [
    (name = "API_KEY", parameter = (type = (text = void))),
    (name = "backend", parameter = (type = (service = void), optional = false)),
  ],
);

const derivedWorker :Workerd.Worker = (
  inherit = "base-worker",
  bindings = [
    (name = "API_KEY", text = "actual-secret-key"),
    (name = "backend", service = "backend-api"),
  ],
);
parameter
group
Declares a required or optional parameter.
  • type: Expected type of the parameter (text, service, durableObjectNamespace, etc.)
  • optional: If true, derived workers need not specify it
Workers with non-optional unfilled parameters can only be used for inheritance, not invoked directly.

Complete example

using Workerd = import "/workerd/workerd.capnp";

const config :Workerd.Config = (
  services = [
    (name = "main", worker = .mainWorker),
    (name = "backend", external = .backendServer),
  ],

  sockets = [
    ( name = "http", address = "*:8080", http = (), service = "main" ),
  ]
);

const mainWorker :Workerd.Worker = (
  modules = [(name = "index.js", esModule = embed "index.js")],
  compatibilityDate = "2023-02-28",

  durableObjectNamespaces = [
    (className = "Counter", uniqueKey = "a1b2c3d4"),
  ],

  durableObjectStorage = (inMemory = void),

  bindings = [
    # Simple data
    (name = "ENVIRONMENT", text = "production"),
    (name = "CONFIG", json = embed "config.json"),
    
    # Services
    (name = "backend", service = "backend"),
    
    # Durable Objects
    (name = "COUNTER", durableObjectNamespace = "Counter"),
    
    # Cache
    (name = "CACHE", memoryCache = (
      id = "main-cache",
      limits = (maxKeys = 1000, maxValueSize = 1048576, maxTotalValueSize = 10485760),
    )),
    
    # Environment variable
    (name = "NODE_ENV", fromEnvironment = "NODE_ENV"),
  ],
);

const backendServer :Workerd.ExternalServer = (
  address = "10.0.1.5:8080",
  http = (),
);

Next steps

Workers

Learn more about worker configuration

Services

Understand service types

Build docs developers (and LLMs) love