Skip to content

Commit c15e99e

Browse files
authored
support using containers with ctx.exports (#11512)
* update containers fixture to use ctx.exports * support containers with DOs using ctx.exports * changeset * print containers * Fix capitalisation in snapshots * PR feedback * fix windows ci * don't rely on migrations only for validation
1 parent 54de499 commit c15e99e

File tree

16 files changed

+608
-147
lines changed

16 files changed

+608
-147
lines changed

.changeset/chatty-doors-shake.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Enable using `ctx.exports` with containers
6+
7+
You can now use containers with Durable Objects that are accessed via [`ctx.exports`](https://developers.cloudflare.com/workers/runtime-apis/context/#exports).
8+
9+
Now your config file can look something like this:
10+
11+
```
12+
{
13+
"name": "container-app",
14+
"main": "src/index.ts",
15+
"compatibility_date": "2025-12-01",
16+
"compatibility_flags": ["enable_ctx_exports"], // compat flag needed for now.
17+
"containers": [
18+
{
19+
"image": "./Dockerfile",
20+
"class_name": "MyDOClassname",
21+
"name": "my-container"
22+
},
23+
],
24+
"migrations": [
25+
{
26+
"tag": "v1",
27+
"new_sqlite_classes": ["MyDOClassname"],
28+
},
29+
],
30+
// no need to declare your durable object binding here
31+
}
32+
```
33+
34+
Note that when using `ctx.exports`, where you previously accessed a Durable Object via something like `env.DO`, you should now access with `ctx.exports.MyDOClassname`.
35+
36+
Refer to [the docs for more information on using `ctx.exports`](https://developers.cloudflare.com/workers/runtime-apis/context/#exports).

fixtures/container-app/src/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,18 @@ export class FixtureTestContainer extends DurableObject<Env> {
5151
}
5252

5353
export default {
54-
async fetch(request, env): Promise<Response> {
54+
async fetch(request, env, ctx: ExecutionContext): Promise<Response> {
5555
const url = new URL(request.url);
5656
if (url.pathname === "/second") {
5757
// This is a second Durable Object that can be used to test multiple DOs
58-
const id = env.CONTAINER.idFromName("second-container");
59-
const stub = env.CONTAINER.get(id);
58+
const id =
59+
ctx.exports.FixtureTestContainer.idFromName("second-container");
60+
const stub = ctx.exports.FixtureTestContainer.get(id);
6061
const query = url.searchParams.get("req");
6162
return stub.fetch("http://example.com/" + query);
6263
}
63-
const id = env.CONTAINER.idFromName("container");
64-
const stub = env.CONTAINER.get(id);
64+
const id = ctx.exports.FixtureTestContainer.idFromName("container");
65+
const stub = ctx.exports.FixtureTestContainer.get(id);
6566
return stub.fetch(request);
6667
},
6768
} satisfies ExportedHandler<Env>;

fixtures/container-app/wrangler.jsonc

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "container-app",
33
"main": "src/index.ts",
44
"compatibility_date": "2025-04-03",
5+
"compatibility_flags": ["enable_ctx_exports"],
56
"containers": [
67
{
78
"image": "./Dockerfile",
@@ -10,14 +11,6 @@
1011
"max_instances": 2,
1112
},
1213
],
13-
"durable_objects": {
14-
"bindings": [
15-
{
16-
"class_name": "FixtureTestContainer",
17-
"name": "CONTAINER",
18-
},
19-
],
20-
},
2114
"migrations": [
2215
{
2316
"tag": "v1",

packages/wrangler/e2e/dev-registry.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ describe.each([{ cmd: "wrangler dev" }])("dev registry $cmd", ({ cmd }) => {
306306
);
307307

308308
expect(normalizeOutput(workerA.currentOutput)).toContain(
309-
"connect to other wrangler or vite dev processes running locally"
309+
"connect to other Wrangler or Vite dev processes running locally"
310310
);
311311
});
312312

@@ -595,7 +595,7 @@ describe.each([{ cmd: "wrangler dev" }])("dev registry $cmd", ({ cmd }) => {
595595
);
596596

597597
expect(normalizeOutput(workerA.currentOutput)).toContain(
598-
"connect to other wrangler or vite dev processes running locally"
598+
"connect to other Wrangler or Vite dev processes running locally"
599599
);
600600
});
601601

packages/wrangler/e2e/pages-dev.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ describe.sequential("wrangler pages dev", () => {
448448
env.VAR1 ("(hidden)") Environment Variable local
449449
env.VAR2 ("VAR_2_TOML") Environment Variable local
450450
env.VAR3 ("(hidden)") Environment Variable local
451-
Service bindings, Durable Object bindings, and Tail consumers connect to other wrangler or vite dev processes running locally, with their connection status indicated by [connected] or [not connected]. For more details, refer to https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/#local-development
451+
Service bindings, Durable Object bindings, and Tail consumers connect to other Wrangler or Vite dev processes running locally, with their connection status indicated by [connected] or [not connected]. For more details, refer to https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/#local-development
452452
"
453453
`);
454454
});

packages/wrangler/src/__tests__/containers/config.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ describe("getNormalizedContainerOptions", () => {
9797
},
9898
],
9999
},
100+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
100101
} as Partial<Config> as Config;
101102

102103
await expect(getNormalizedContainerOptions(config, {})).rejects.toThrow(
@@ -132,6 +133,7 @@ describe("getNormalizedContainerOptions", () => {
132133
},
133134
],
134135
},
136+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
135137
} as Partial<Config> as Config;
136138

137139
const result = await getNormalizedContainerOptions(config, {});
@@ -176,6 +178,7 @@ describe("getNormalizedContainerOptions", () => {
176178
},
177179
],
178180
},
181+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
179182
} as Partial<Config> as Config;
180183

181184
const result = await getNormalizedContainerOptions(config, {});
@@ -219,6 +222,7 @@ describe("getNormalizedContainerOptions", () => {
219222
},
220223
],
221224
},
225+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
222226
} as Partial<Config> as Config;
223227

224228
const result = await getNormalizedContainerOptions(config, {});
@@ -260,6 +264,7 @@ describe("getNormalizedContainerOptions", () => {
260264
},
261265
],
262266
},
267+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
263268
} as Partial<Config> as Config;
264269

265270
const result = await getNormalizedContainerOptions(config, {});
@@ -307,6 +312,7 @@ describe("getNormalizedContainerOptions", () => {
307312
},
308313
],
309314
},
315+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
310316
} as Partial<Config> as Config;
311317

312318
const result = await getNormalizedContainerOptions(config, {});
@@ -351,6 +357,7 @@ describe("getNormalizedContainerOptions", () => {
351357
},
352358
],
353359
},
360+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
354361
} as Partial<Config> as Config;
355362

356363
const result = await getNormalizedContainerOptions(config, {});
@@ -393,6 +400,7 @@ describe("getNormalizedContainerOptions", () => {
393400
},
394401
],
395402
},
403+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
396404
} as Partial<Config> as Config;
397405

398406
const result = await getNormalizedContainerOptions(config, {});
@@ -448,6 +456,7 @@ describe("getNormalizedContainerOptions", () => {
448456
},
449457
],
450458
},
459+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
451460
} as Partial<Config> as Config;
452461

453462
const result = await getNormalizedContainerOptions(config, {});
@@ -500,6 +509,7 @@ describe("getNormalizedContainerOptions", () => {
500509
},
501510
],
502511
},
512+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
503513
} as Partial<Config> as Config;
504514

505515
const result = await getNormalizedContainerOptions(config, {});
@@ -552,6 +562,9 @@ describe("getNormalizedContainerOptions", () => {
552562
},
553563
],
554564
},
565+
migrations: [
566+
{ tag: "v1", new_sqlite_classes: ["Container1", "Container2"] },
567+
],
555568
} as Partial<Config> as Config;
556569

557570
const result = await getNormalizedContainerOptions(config, {});
@@ -583,6 +596,7 @@ describe("getNormalizedContainerOptions", () => {
583596
},
584597
],
585598
},
599+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
586600
} as Partial<Config> as Config;
587601

588602
const result = await getNormalizedContainerOptions(config, {});
@@ -615,6 +629,7 @@ describe("getNormalizedContainerOptions", () => {
615629
},
616630
],
617631
},
632+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
618633
} as Partial<Config> as Config;
619634

620635
const result = await getNormalizedContainerOptions(config, {});
@@ -644,6 +659,7 @@ describe("getNormalizedContainerOptions", () => {
644659
},
645660
],
646661
},
662+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
647663
} as Partial<Config> as Config;
648664

649665
const result = await getNormalizedContainerOptions(config, {});
@@ -675,6 +691,7 @@ describe("getNormalizedContainerOptions", () => {
675691
},
676692
],
677693
},
694+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
678695
} as Partial<Config> as Config;
679696
const result = await getNormalizedContainerOptions(config, {});
680697
expect(result).toHaveLength(1);
@@ -705,6 +722,7 @@ describe("getNormalizedContainerOptions", () => {
705722
},
706723
],
707724
},
725+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
708726
} as Partial<Config> as Config;
709727
const result = await getNormalizedContainerOptions(config, {});
710728
expect(result).toHaveLength(1);
@@ -736,6 +754,7 @@ describe("getNormalizedContainerOptions", () => {
736754
},
737755
],
738756
},
757+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
739758
} as Partial<Config> as Config;
740759
const result = await getNormalizedContainerOptions(config, {
741760
dryRun: true,

0 commit comments

Comments
 (0)