2.0.0-beta.57 - Containers in Dev & AI Search
Cloudflare Containers now run locally under alchemy dev — the
same Container + Durable Object code that deploys to Cloudflare’s
network docker-builds and runs on your machine, no code changes.
beta.57 also adds Cloudflare AI Search (AutoRAG) as a one-call
construct with a typed Worker binding, and a large AWS coverage wave.
Containers run locally in alchemy dev
Section titled “Containers run locally in alchemy dev”A Container class is unchanged — declare its identity and props,
provide the runtime implementation with .make():
export class SandboxContainer extends Cloudflare.Container< SandboxContainer, {}>()("SandboxContainer", { main: import.meta.filename, instanceType: "dev",}) {}
export default SandboxContainer.make( Effect.gen(function* () { return SandboxContainer.of({ fetch: Effect.succeed( HttpServerResponse.text("Hello from Sandbox container!"), ), }); }),);A Durable Object binds it, starts it, and talks to it over a TCP port — again, nothing dev-specific:
export default class SandboxDO extends Cloudflare.DurableObjectNamespace<SandboxDO>()( "SandboxDO", Effect.gen(function* () { const sandbox = yield* Cloudflare.Container.bind(SandboxContainer);
return Effect.gen(function* () { const container = yield* Cloudflare.start(sandbox, { enableInternet: true, });
return { fetch: Effect.gen(function* () { const { fetch } = yield* container.getTcpPort(3000); const response = yield* fetch( HttpClientRequest.get("http://container/"), ); return HttpServerResponse.text(yield* response.text); }), }; }); }),) {}As of beta.57, alchemy dev runs that container on your machine: the
container program is bundled with rolldown, a Dockerfile is generated
(FROM oven/bun:1 or node:22-slim depending on the container’s
runtime, auto-installing any declared externals), and the local
runtime docker-builds the image and wires it into the local Durable
Object namespace.
bun alchemy devcurl http://localhost:1338/sandbox# Hello from Sandbox container!Dev-created containers carry a dev:<uuid> application id, so a
subsequent alchemy deploy knows to promote them to a real
ContainerApplication
(#636).
Cloudflare AI Search (AutoRAG)
Section titled “Cloudflare AI Search (AutoRAG)”Cloudflare.AiSearch stands up a full retrieval-augmented-generation
pipeline over an R2 bucket — chunking, embedding, vector search,
reranking, and generation, all managed by Cloudflare:
export const Docs = Cloudflare.R2Bucket("Docs", {});
export const Search = Cloudflare.AiSearch("Search", { source: Docs,});It’s a construct, not a single resource: for an R2 source it
provisions a least-privilege AccountApiToken scoped to the AI Search
Index Engine permission group, wraps it in the AiSearchToken service
token the indexer requires, and creates the AiSearchInstance with
everything wired together. Pass a URL as source instead and it
indexes a website via the web crawler; prefix / include /
exclude globs scope what gets indexed.
Cloudflare.AiSearchInstance.bind(search) gives a Worker a typed
Effect client — chatCompletions for full RAG, search for
retrieval-only:
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.filename }, Effect.gen(function* () { const aiSearch = yield* Search; const search = yield* Cloudflare.AiSearchInstance.bind(aiSearch);
return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; const url = new URL(request.url, "http://api"); const query = url.searchParams.get("q") ?? "What is this about?";
const answer = yield* search .chatCompletions({ messages: [{ role: "user", content: query }] }) .pipe(Effect.orDie);
return yield* HttpServerResponse.json({ response: answer.choices[0]?.message.content, sources: answer.chunks.map((c) => c.item.key), }); }), }; }).pipe(Effect.provide(Cloudflare.AiSearchInstanceBindingLive)),) {}answer.chunks are the source chunks the answer drew from, so
citations come for free. The binding also works in alchemy dev. The
new AI Search tutorial walks through
the whole pipeline, including dropping down to the underlying
AiSearchInstance / AiSearchNamespace / AiSearchToken resources
(#639).
An AWS coverage wave
Section titled “An AWS coverage wave”Five new resources land in one PR
(#631):
CloudFront VpcOrigin, ELBv2 ListenerRule and
TrustStore (mTLS), and Route53 HostedZone and
HealthCheck — each with live tests.
Existing resources get much deeper. S3 Bucket alone gains
encryption (SSE-KMS/DSSE), public access block, CORS, lifecycle
rules, object ownership/ACL, access logging, website hosting,
replication, intelligent tiering, object lock, and inline policy:
const site = yield* S3.Bucket("Site", { versioning: "Enabled", encryption: { sseAlgorithm: "aws:kms", bucketKeyEnabled: true }, publicAccessBlock: { blockPublicAcls: true, blockPublicPolicy: true }, lifecycleRules: [ { ID: "expire-old", Status: "Enabled", Filter: { Prefix: "logs/" }, Expiration: { Days: 30 }, }, ], website: { indexDocument: { suffix: "index.html" } },});CloudFront Distribution picks up origin groups, geo restriction,
access logging, trusted key groups, origin shield, VPC origins, and
gRPC; Route53 Record gains routing policies; and RDS, ECS, ELBv2,
and SQS props all deepen — about 8,700 lines in total.
KMS keys, Lambda aliases, log-group config
Section titled “KMS keys, Lambda aliases, log-group config”Thanks José Netto for a run of AWS contributions: new
AWS.KMS.Key and AWS.KMS.Alias resources
(#641),
a Lambda Alias resource
(#625),
reservedConcurrentExecutions on Lambda Function
(#628),
and LogGroup configuration — retention, KMS encryption, log class,
and deletion protection
(#630).
const key = yield* KMS.Key("AppKey", { description: "Application encryption key", enableKeyRotation: true,});
yield* KMS.Alias("AppAlias", { aliasName: "alias/app", targetKeyId: key.keyId,});
const logs = yield* LogGroup("ApiLogs", { retentionInDays: 30, kmsKeyId: key.keyArn,});Weighted alias routing shifts traffic between Lambda versions declaratively:
const alias = yield* Lambda.Alias("LiveAlias", { functionName: fn.functionName, functionVersion: "2", aliasName: "live", routingConfig: { AdditionalVersionWeights: { "3": 0.1 }, },});Hardening the Cloudflare fleet
Section titled “Hardening the Cloudflare fleet”beta.56 grew the Cloudflare provider 10x
in one release; beta.57 is the flywheel’s second turn — stabilizing
that fleet against the real API. Live tests flagged rough edges in
PageRule, Schema Validation, Images Variant, origin post-quantum
encryption, Origin TLS client auth, and Pages Project, and each fix
followed the same doctrine: patch the distilled SDK so the API’s
actual behavior becomes a typed error tag, regenerate, and handle
the tag — never a status-code check in alchemy code. The distilled
submodule was repatched and regenerated six times during this release.
Quota- and entitlement-bound live tests now skip cleanly instead of
failing, and transient errors retry on their exact typed tag — e.g.
Magic Network Monitoring retries MnnConfigMissing — so an entitled
account runs the full suite unchanged.
Also in this release
Section titled “Also in this release”diff.stablesoverridesprovider.stables— a provider’s diff can now narrow stability per-update, fixing spurious replacements (#635).- Atomic local state writes —
LocalStatewrites to a temp file and renames, so a crash mid-write can’t corrupt state. alchemy devno longer watchesnode_modules, cutting file-watcher churn on large projects (#646).- Queue consumers created in dev promote cleanly to a real deploy (#647).
- Local service bindings preserve their entrypoints in dev. Thanks Jonathan Beckman (#643).
- AI Search bindings work in local dev. Thanks Jonathan Beckman (#642).
alchemy cloudflare create-tokencan now mint user API tokens and interactively select permissions.Build.Commandhandles both relative and absolute paths.Artifacts.cachedis allowed in the localRpcProvider(#648).- GitHub
Repositorydocs — examples for templates, rename, archive, and secrets. Thanks Justin Bennett (#629). - AWS lifecycle hardening — Scheduler, SQS DLQ wiring, SNS Topic, CloudFront, DynamoDB, EC2, IAM, and Kinesis operations retry eventual consistency and throttling more robustly.
- Cloudflare provider docs reorganized and categorized, with missing pages added.