1---
2title: 2.0.0-beta.57 - Containers in Dev & AI Search
3date: 2026-06-19T20:00:00Z
4category: release
5excerpt: v2.0.0-beta.57 runs Cloudflare Containers locally in `alchemy dev`, adds Cloudflare AI Search (AutoRAG) with a typed Worker binding, and lands a large AWS wave — CloudFront VpcOrigin, ELBv2 ListenerRule & TrustStore, Route53 HostedZone & HealthCheck, KMS keys, and Lambda aliases.
6---
7
8Cloudflare Containers now run **locally** under `alchemy dev` — the
9same Container + Durable Object code that deploys to Cloudflare's
10network docker-builds and runs on your machine, no code changes.
11beta.57 also adds **Cloudflare AI Search** (AutoRAG) as a one-call
12construct with a typed Worker binding, and a large AWS coverage wave.
13
14:::caution
15**effect is bumped to `4.0.0-beta.84`** — update your `effect`
16dependency to match. Upstream renamed `ConfigProvider.get` to
17`ConfigProvider.load`, so any direct `ConfigProvider` usage needs the
18same one-line rename. No alchemy APIs changed.
19:::
20
21## Containers run locally in `alchemy dev`
22
23A `Container` class is unchanged — declare its identity and props,
24provide the runtime implementation with `.make()`:
25
26```typescript
27// src/SandboxContainer.ts
28export class SandboxContainer extends Cloudflare.Container<
29 SandboxContainer,
30 {}
31>()("SandboxContainer", {
32 main: import.meta.filename,
33 instanceType: "dev",
34}) {}
35
36export default SandboxContainer.make(
37 Effect.gen(function* () {
38 return SandboxContainer.of({
39 fetch: Effect.succeed(
40 HttpServerResponse.text("Hello from Sandbox container!"),
41 ),
42 });
43 }),
44);
45```
46
47A Durable Object binds it, starts it, and talks to it over a TCP
48port — again, nothing dev-specific:
49
50```typescript
51// src/SandboxDO.ts
52export default class SandboxDO extends Cloudflare.DurableObjectNamespace<SandboxDO>()(
53 "SandboxDO",
54 Effect.gen(function* () {
55 const sandbox = yield* Cloudflare.Container.bind(SandboxContainer);
56
57 return Effect.gen(function* () {
58 const container = yield* Cloudflare.start(sandbox, {
59 enableInternet: true,
60 });
61
62 return {
63 fetch: Effect.gen(function* () {
64 const { fetch } = yield* container.getTcpPort(3000);
65 const response = yield* fetch(
66 HttpClientRequest.get("http://container/"),
67 );
68 return HttpServerResponse.text(yield* response.text);
69 }),
70 };
71 });
72 }),
73) {}
74```
75
76As of beta.57, `alchemy dev` runs that container on your machine: the
77container program is bundled with rolldown, a Dockerfile is generated
78(`FROM oven/bun:1` or `node:22-slim` depending on the container's
79`runtime`, auto-installing any declared externals), and the local
80runtime docker-builds the image and wires it into the local Durable
81Object namespace.
82
83```sh
84bun alchemy dev
85curl http://localhost:1338/sandbox
86# Hello from Sandbox container!
87```
88
89Dev-created containers carry a `dev:<uuid>` application id, so a
90subsequent `alchemy deploy` knows to promote them to a real
91`ContainerApplication`
92([#636](https://github.com/alchemy-run/alchemy/pull/636)).
93
94## Cloudflare AI Search (AutoRAG)
95
96`Cloudflare.AiSearch` stands up a full retrieval-augmented-generation
97pipeline over an R2 bucket — chunking, embedding, vector search,
98reranking, and generation, all managed by Cloudflare:
99
100```typescript
101export const Docs = Cloudflare.R2Bucket("Docs", {});
102
103export const Search = Cloudflare.AiSearch("Search", {
104 source: Docs,
105});
106```
107
108It's a **construct**, not a single resource: for an R2 source it
109provisions a least-privilege `AccountApiToken` scoped to the AI Search
110Index Engine permission group, wraps it in the `AiSearchToken` service
111token the indexer requires, and creates the `AiSearchInstance` with
112everything wired together. Pass a URL as `source` instead and it
113indexes a website via the web crawler; `prefix` / `include` /
114`exclude` globs scope what gets indexed.
115
116`Cloudflare.AiSearchInstance.bind(search)` gives a Worker a typed
117Effect client — `chatCompletions` for full RAG, `search` for
118retrieval-only:
119
120```typescript
121export default class Api extends Cloudflare.Worker<Api>()(
122 "Api",
123 { main: import.meta.filename },
124 Effect.gen(function* () {
125 const aiSearch = yield* Search;
126 const search = yield* Cloudflare.AiSearchInstance.bind(aiSearch);
127
128 return {
129 fetch: Effect.gen(function* () {
130 const request = yield* HttpServerRequest;
131 const url = new URL(request.url, "http://api");
132 const query = url.searchParams.get("q") ?? "What is this about?";
133
134 const answer = yield* search
135 .chatCompletions({ messages: [{ role: "user", content: query }] })
136 .pipe(Effect.orDie);
137
138 return yield* HttpServerResponse.json({
139 response: answer.choices[0]?.message.content,
140 sources: answer.chunks.map((c) => c.item.key),
141 });
142 }),
143 };
144 }).pipe(Effect.provide(Cloudflare.AiSearchInstanceBindingLive)),
145) {}
146```
147
148`answer.chunks` are the source chunks the answer drew from, so
149citations come for free. The binding also works in `alchemy dev`. The
150new [AI Search tutorial](/cloudflare/ai/ai-search) walks through
151the whole pipeline, including dropping down to the underlying
152`AiSearchInstance` / `AiSearchNamespace` / `AiSearchToken` resources
153([#639](https://github.com/alchemy-run/alchemy/pull/639)).
154
155## An AWS coverage wave
156
157Five new resources land in one PR
158([#631](https://github.com/alchemy-run/alchemy/pull/631)):
159CloudFront **`VpcOrigin`**, ELBv2 **`ListenerRule`** and
160**`TrustStore`** (mTLS), and Route53 **`HostedZone`** and
161**`HealthCheck`** — each with live tests.
162
163Existing resources get much deeper. S3 `Bucket` alone gains
164encryption (SSE-KMS/DSSE), public access block, CORS, lifecycle
165rules, object ownership/ACL, access logging, website hosting,
166replication, intelligent tiering, object lock, and inline `policy`:
167
168```typescript
169const site = yield* S3.Bucket("Site", {
170 versioning: "Enabled",
171 encryption: { sseAlgorithm: "aws:kms", bucketKeyEnabled: true },
172 publicAccessBlock: { blockPublicAcls: true, blockPublicPolicy: true },
173 lifecycleRules: [
174 {
175 ID: "expire-old",
176 Status: "Enabled",
177 Filter: { Prefix: "logs/" },
178 Expiration: { Days: 30 },
179 },
180 ],
181 website: { indexDocument: { suffix: "index.html" } },
182});
183```
184
185CloudFront `Distribution` picks up origin groups, geo restriction,
186access logging, trusted key groups, origin shield, VPC origins, and
187gRPC; Route53 `Record` gains routing policies; and RDS, ECS, ELBv2,
188and SQS props all deepen — about 8,700 lines in total.
189
190## KMS keys, Lambda aliases, log-group config
191
192Thanks **José Netto** for a run of AWS contributions: new
193`AWS.KMS.Key` and `AWS.KMS.Alias` resources
194([#641](https://github.com/alchemy-run/alchemy/pull/641)),
195a Lambda `Alias` resource
196([#625](https://github.com/alchemy-run/alchemy/pull/625)),
197`reservedConcurrentExecutions` on Lambda `Function`
198([#628](https://github.com/alchemy-run/alchemy/pull/628)),
199and `LogGroup` configuration — retention, KMS encryption, log class,
200and deletion protection
201([#630](https://github.com/alchemy-run/alchemy/pull/630)).
202
203```typescript
204const key = yield* KMS.Key("AppKey", {
205 description: "Application encryption key",
206 enableKeyRotation: true,
207});
208
209yield* KMS.Alias("AppAlias", {
210 aliasName: "alias/app",
211 targetKeyId: key.keyId,
212});
213
214const logs = yield* LogGroup("ApiLogs", {
215 retentionInDays: 30,
216 kmsKeyId: key.keyArn,
217});
218```
219
220Weighted alias routing shifts traffic between Lambda versions
221declaratively:
222
223```typescript
224const alias = yield* Lambda.Alias("LiveAlias", {
225 functionName: fn.functionName,
226 functionVersion: "2",
227 aliasName: "live",
228 routingConfig: {
229 AdditionalVersionWeights: { "3": 0.1 },
230 },
231});
232```
233
234## Hardening the Cloudflare fleet
235
236[beta.56](/blog/2026-06-17-beta-56) grew the Cloudflare provider 10x
237in one release; beta.57 is the flywheel's second turn — stabilizing
238that fleet against the real API. Live tests flagged rough edges in
239PageRule, Schema Validation, Images `Variant`, origin post-quantum
240encryption, Origin TLS client auth, and Pages `Project`, and each fix
241followed the same doctrine: patch the distilled SDK so the API's
242actual behavior becomes a **typed error tag**, regenerate, and handle
243the tag — never a status-code check in alchemy code. The distilled
244submodule was repatched and regenerated six times during this release.
245Quota- and entitlement-bound live tests now skip cleanly instead of
246failing, and transient errors retry on their exact typed tag — e.g.
247Magic Network Monitoring retries `MnnConfigMissing` — so an entitled
248account runs the full suite unchanged.
249
250## Also in this release
251
252- **`diff.stables` overrides `provider.stables`** — a provider's diff
253 can now narrow stability per-update, fixing spurious replacements
254 ([#635](https://github.com/alchemy-run/alchemy/pull/635)).
255- **Atomic local state writes** — `LocalState` writes to a temp file
256 and renames, so a crash mid-write can't corrupt state.
257- **`alchemy dev` no longer watches `node_modules`**, cutting
258 file-watcher churn on large projects
259 ([#646](https://github.com/alchemy-run/alchemy/pull/646)).
260- **Queue consumers created in dev promote cleanly** to a real deploy
261 ([#647](https://github.com/alchemy-run/alchemy/pull/647)).
262- **Local service bindings preserve their entrypoints** in dev. Thanks
263 **Jonathan Beckman**
264 ([#643](https://github.com/alchemy-run/alchemy/pull/643)).
265- **AI Search bindings work in local dev**. Thanks
266 **Jonathan Beckman**
267 ([#642](https://github.com/alchemy-run/alchemy/pull/642)).
268- **`alchemy cloudflare create-token`** can now mint user API tokens
269 and interactively select permissions.
270- **`Build.Command`** handles both relative and absolute paths.
271- **`Artifacts.cached`** is allowed in the local `RpcProvider`
272 ([#648](https://github.com/alchemy-run/alchemy/pull/648)).
273- **GitHub `Repository` docs** — examples for templates, rename,
274 archive, and secrets. Thanks **Justin Bennett**
275 ([#629](https://github.com/alchemy-run/alchemy/pull/629)).
276- **AWS lifecycle hardening** — Scheduler, SQS DLQ wiring, SNS Topic,
277 CloudFront, DynamoDB, EC2, IAM, and Kinesis operations retry
278 eventual consistency and throttling more robustly.
279- **Cloudflare provider docs** reorganized and categorized, with
280 missing pages added.
281
282## Where to go next
283
284- [Add AI Search (AutoRAG)](/cloudflare/ai/ai-search)
285- [Run a Container](/cloudflare/compute/run-a-container)
286- [Add a Durable Object](/cloudflare/compute/durable-objects)
287- [CHANGELOG](https://github.com/alchemy-run/alchemy/blob/main/CHANGELOG.md#v200-beta57)
288- [Compare v2.0.0-beta.56 → v2.0.0-beta.57](https://github.com/alchemy-run/alchemy/compare/v2.0.0-beta.56...v2.0.0-beta.57)