You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform. Bindings provide better performance and less restrictions when accessing resources from Workers than the [REST APIs](/api/) which are intended for non-Workers applications.
12
11
@@ -31,12 +30,12 @@ r2_buckets = [
31
30
32
31
```js
33
32
exportdefault {
34
-
asyncfetch(request, env) {
35
-
constkey=url.pathname.slice(1);
36
-
awaitenv.MY_BUCKET.put(key, request.body);
37
-
returnnewResponse(`Put ${key} successfully!`);
38
-
}
39
-
}
33
+
asyncfetch(request, env) {
34
+
constkey=url.pathname.slice(1);
35
+
awaitenv.MY_BUCKET.put(key, request.body);
36
+
returnnewResponse(`Put ${key} successfully!`);
37
+
},
38
+
};
40
39
```
41
40
42
41
You can think of a binding as a permission and an API in one piece. With bindings, you never have to add secret keys or tokens to your Worker in order to access resources on your Cloudflare account — the permission is embedded within the API itself. The underlying secret is never exposed to your Worker's code, and therefore can't be accidentally leaked.
@@ -51,12 +50,12 @@ The following is a good approach:
51
50
52
51
```ts
53
52
exportdefault {
54
-
fetch(request, env) {
55
-
let client =newClient(env.MY_SECRET); // `client` is guaranteed to be up-to-date with the latest value of `env.MY_SECRET` since a new instance is constructed with every incoming request
53
+
fetch(request, env) {
54
+
let client =newClient(env.MY_SECRET); // `client` is guaranteed to be up-to-date with the latest value of `env.MY_SECRET` since a new instance is constructed with every incoming request
56
55
57
-
// ... do things with `client`
58
-
}
59
-
}
56
+
// ... do things with `client`
57
+
},
58
+
};
60
59
```
61
60
62
61
Compared to this alternative, which might have surprising and unwanted behavior:
@@ -65,12 +64,153 @@ Compared to this alternative, which might have surprising and unwanted behavior:
65
64
let client =undefined;
66
65
67
66
exportdefault {
68
-
fetch(request, env) {
69
-
client??=newClient(env.MY_SECRET); // `client` here might not be updated when `env.MY_SECRET` changes, since it may already exist in global scope
67
+
fetch(request, env) {
68
+
client??=newClient(env.MY_SECRET); // `client` here might not be updated when `env.MY_SECRET` changes, since it may already exist in global scope
69
+
70
+
// ... do things with `client`
71
+
},
72
+
};
73
+
```
74
+
75
+
If you have more advanced needs, explore the [AsyncLocalStorage API](/workers/runtime-apis/nodejs/asynclocalstorage/), which provides a mechanism for exposing values down to child execution handlers.
76
+
77
+
## How to access `env`
78
+
79
+
Bindings are located on the `env` object, which can be accessed in several ways:
80
+
81
+
- It is an argument to entrypoint handlers such as [`fetch`](/workers/runtime-apis/fetch/):
82
+
83
+
```js
84
+
exportdefault {
85
+
asyncfetch(request, env) {
86
+
returnnewResponse(`Hi, ${env.NAME}`);
87
+
},
88
+
};
89
+
```
70
90
71
-
// ... do things with `client`
91
+
* It is as class property on [WorkerEntrypoint](/workers/runtime-apis/bindings/service-bindings/rpc/#bindings-env),
92
+
[DurableObject](/durable-objects/), and [Workflow](/workflows/):
93
+
94
+
```js
95
+
exportclassMyDurableObjectextendsDurableObject {
96
+
asyncsayHello() {
97
+
return`Hi, ${this.env.NAME}!`;
98
+
}
72
99
}
100
+
```
101
+
102
+
* It can be imported from `cloudflare:workers`:
103
+
104
+
```js
105
+
import { env } from"cloudflare:workers";
106
+
console.log(`Hi, ${this.env.Name}`);
107
+
```
108
+
109
+
### Importing `env` as a global
110
+
111
+
Importing `env` from `cloudflare:workers` is useful when you need to access a binding
112
+
such as [secrets](/workers/configuration/secrets/) or [environment variables](/workers/configuration/environment-variables/)
113
+
in top-level global scope. For example, to initialize an API client:
114
+
115
+
```js
116
+
import { env } from"cloudflare:workers";
117
+
importApiClientfrom"example-api-client";
118
+
119
+
// API_KEY and LOG_LEVEL now usable in top-level scope
120
+
let apiClient =ApiClient.new({ apiKey:env.API_KEY });
121
+
constLOG_LEVEL=env.LOG_LEVEL||"info";
122
+
123
+
exportdefault {
124
+
fetch(req) {
125
+
// you can use apiClient or LOG_LEVEL, configured before any request is handled
126
+
},
127
+
};
128
+
```
129
+
130
+
Workers do not allow I/O from outside a request context. This means that even
131
+
though `env` is accessible from the top-level scope, you will not be able to access
132
+
every binding's methods.
133
+
134
+
For instance, environment variables and secrets are accessible, and you are able to
135
+
call `env.NAMESPACE.get` to get a [Durable Object stub](/durable-objects/api/stub/) in the
136
+
top-level context. However, calling methods on the Durable Object stub, making [calls to a KV store](/kv/api/),
137
+
and [calling to other Workers](/workers/runtime-apis/bindings/service-bindings) will not work.
138
+
139
+
```js
140
+
import { env } from"cloudflare:workers";
141
+
142
+
// This would error!
143
+
// env.KV.get('my-key')
144
+
145
+
exportdefault {
146
+
asyncfetch(req) {
147
+
// This works
148
+
let myVal =awaitenv.KV.get("my-key");
149
+
Response.new(myVal);
150
+
},
151
+
};
152
+
```
153
+
154
+
Additionally, importing `env` from `cloudflare:workers` lets you avoid passing `env`
155
+
as an argument through many function calls if you need to access a binding from a deeply-nested
156
+
function. This can be helpful in a complex codebase.
157
+
158
+
```js
159
+
import { env } from"cloudflare:workers";
160
+
161
+
exportdefault {
162
+
fetch(req) {
163
+
Response.new(sayHello());
164
+
},
165
+
};
166
+
167
+
// env is not an argument to sayHello...
168
+
functionsayHello() {
169
+
let myName =getName();
170
+
return`Hello, ${myName}`;
171
+
}
172
+
173
+
// ...nor is it an argument to getName
174
+
functiongetName() {
175
+
returnenv.MY_NAME;
73
176
}
74
177
```
75
178
76
-
If you have more advanced needs, explore the [AsyncLocalStorage API](/workers/runtime-apis/nodejs/asynclocalstorage/), which provides a mechanism for exposing values down to child execution handlers.
179
+
:::note
180
+
While using `env` from `cloudflare:workers` may be simpler to write than passing it
181
+
through a series of function calls, passing `env` as an argument is a helpful pattern
182
+
for dependency injection and testing.
183
+
:::
184
+
185
+
### Overriding `env` values
186
+
187
+
The `withEnv` function provides a mechanism for overriding values of `env`.
188
+
189
+
Imagine a user has defined the [environment variable](/workers/configuration/environment-variables/)
190
+
"NAME" to be "Alice" in their Wrangler configuration file and deployed a Worker. By default, logging
191
+
`env.NAME` would print "Alice". Using the `withEnv` function, you can override the value of
192
+
"NAME".
193
+
194
+
```js
195
+
import { env, withEnv } from"cloudflare:workers";
196
+
197
+
functionlogName() {
198
+
console.log(env.NAME);
199
+
}
200
+
201
+
exportdefault {
202
+
fetch(req) {
203
+
// this will log "Alice"
204
+
logName();
205
+
206
+
withEnv({ NAME:"Bob" }, () => {
207
+
// this will log "Bob"
208
+
logName();
209
+
});
210
+
211
+
// ...etc...
212
+
},
213
+
};
214
+
```
215
+
216
+
This can be useful when testing code that relies on an imported `env` object.
0 commit comments