Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 292 additions & 0 deletions website/src/content/docs/blog/2026-07-06-beta-60.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
---
title: 2.0.0-beta.60 - Docker, MicroVMs & RSC
date: 2026-07-06T22:00:00Z
category: release
excerpt: v2.0.0-beta.60 adds a Docker provider, AWS Lambda MicroVMs, Workers for Platforms, React Server Components on Vite, class-based Workflows on async Workers, dramatically faster Cloudflare Container starts, and a ground-up docs overhaul.
---

beta.60 is a big one: a new **Docker provider**, **AWS Lambda
MicroVMs**, **Workers for Platforms**, **React Server Components**
on the Vite pipeline, class-based **Workflows on async Workers**,
Cloudflare **Containers** that start fast and stay up, and a
ground-up overhaul of the docs. No breaking changes this release.

## Docker provider

`alchemy/Docker` brings `Image`, `RemoteImage`, `Container`,
`Volume`, and `Network` as Stack resources
([#649](https://github.com/alchemy-run/alchemy-effect/pull/649)).
They drive the `docker` CLI's active context — Docker Desktop, a
remote/SSH context, a CI daemon — and live in the same Stack as
your cloud resources. Thanks **Austin**!

```typescript
const image = yield* Docker.RemoteImage("postgres-image", {
name: "postgres",
tag: "18-alpine",
});
const network = yield* Docker.Network("app-network");
const data = yield* Docker.Volume("postgres-data");

const postgres = yield* Docker.Container("postgres", {
image,
environment: { POSTGRES_PASSWORD: password }, // Redacted-safe
ports: [{ external: 15432, internal: 5432 }],
volumes: [{ hostPath: data.name, containerPath: "/var/lib/postgresql/data" }],
networks: [{ name: network.name, aliases: ["postgres"] }],
start: true,
});
```

Secrets are passed via process env (never on the CLI), pulled tags
are pinned so re-deploys are no-ops, and containers created outside
alchemy follow the standard adoption rules. See the new
[Docker hub](/docker) and the
[local services guide](/docker/local-services).

## AWS Lambda MicroVMs

`AWS.Lambda.MicrovmImage` is a new Platform for snapshot-booted
microVMs ([#712](https://github.com/alchemy-run/alchemy-effect/pull/712)).
Author the in-VM server in TypeScript — alchemy bundles it,
generates the Dockerfile, and builds the snapshot server-side — or
bring your own Dockerfile or a prebuilt artifact:

```typescript
export class Sandbox extends AWS.Lambda.MicrovmImage<
Sandbox,
{ hello: (message: string) => Effect.Effect<string> }
>()("Sandbox") {}

export default Sandbox.make(
{ main: import.meta.filename, buildRole },
Effect.gen(function* () {
return {
hello: (message) => Effect.succeed(`hello, ${message}!`),
fetch: Effect.gen(function* () { /* raw HTTP route */ }),
};
}),
);
```

Every instance operation — `RunMicrovm`, `GetMicrovm`,
suspend/resume/terminate, auth tokens, image builds — is a
`Binding.Service` with least-privilege IAM scoping, and
`connectMicrovm` gives you typed RPC into the running VM:

```typescript
const sandbox = yield* AWS.Lambda.connectMicrovm(Sandbox, { endpoint, authToken });
const reply = yield* sandbox.hello("world");
```

It works cross-cloud too: binding a MicroVM operation from a
`Cloudflare.Worker` mints an IAM user + assume-role Role so the
Worker can drive AWS MicroVMs at runtime.

We also benchmarked MicroVMs against Cloudflare Containers — 700
isolated cold boots. MicroVMs boot in 2–4.5s regardless of what's
inside; full results in
[Benchmarking Cloudflare Containers vs AWS MicroVMs](/blog/2026-07-01-microvm-cold-starts).
Docs: [MicroVMs](/aws/compute/microvms).

## Workers for Platforms

Deploy user Workers into a dispatch namespace and route to them
dynamically ([#715](https://github.com/alchemy-run/alchemy-effect/pull/715)).
A Worker deploys *into* a namespace with the new `namespace` prop —
no duplicate resource type:

```typescript
const ns = yield* Cloudflare.WorkersForPlatforms.DispatchNamespace("Customers", {});

const userWorker = yield* Cloudflare.Worker("CustomerA", {
namespace: ns.name,
script: `export default { fetch() { return new Response("hi") } }`,
});
```

The platform Worker binds the namespace Effect-natively, or via
`env` for async Workers:

```typescript
// Effect-native — yield the binding, get a typed client
const dispatch = yield* Cloudflare.WorkersForPlatforms.Get(namespace);
const userWorker = yield* dispatch.get("customer-a");
```

```typescript
// async — DispatchNamespace is a valid env binding
const platform = Cloudflare.Worker("Platform", {
main: "./handler.ts",
env: { DISPATCH: namespace },
});
// handler.ts: env.DISPATCH.get("customer-a").fetch(request)
```

Docs: [Workers for Platforms](/cloudflare/compute/workers-for-platforms).

## React Server Components on Vite

`Cloudflare.Vite` now supports builds that emit more than one
server environment — most notably RSC
([#685](https://github.com/alchemy-run/alchemy-effect/pull/685)).
`viteEnvironments` selects which environment produces the deployed
Worker entry and which additional server environments are bundled
alongside it:

```typescript
const app = yield* Cloudflare.Vite("ReactRouterRSC", {
compatibility: { flags: ["nodejs_compat"] },
viteEnvironments: { entry: "rsc", children: ["ssr"] },
});
```

A single-environment SSR build needs no configuration — the
default is `{ entry: "ssr", children: [] }` — and the `client`
environment always deploys as static assets. The same PR replaces
the dev-server restart fingerprint with an exact structural
signature, so config changes are never silently missed. Docs:
[Frontends on Cloudflare](/cloudflare/frontend/frontends).

## Workflows on async Workers

Class-based Cloudflare Workflows now bind to async (non-Effect)
Workers via `env`, mirroring class-based Durable Objects
([#707](https://github.com/alchemy-run/alchemy-effect/pull/707)):

```typescript
export const AsyncWorker = Cloudflare.Worker("Async", {
main: "./src/worker.ts",
env: {
MY_WORKFLOW: Cloudflare.Workflow<{ value: string }>("MyWorkflow", {
className: "MyWorkflow",
}),
},
});
export type Env = Cloudflare.InferEnv<typeof AsyncWorker>;
// env.MY_WORKFLOW is the native Workflow<{ value: string }>
```

Your `WorkflowEntrypoint` class stays plain `cloudflare:workers`
code; alchemy provisions the workflow and emits the binding.
Cross-script references work with `scriptName`, same as async DOs.
Docs: [Workflows](/cloudflare/compute/workflows).

## Containers start fast and stay up

Cloudflare Containers deployed with alchemy behaved much worse
than the same image deployed with wrangler — at 100 concurrent
cold starts, ~2/100 succeeded. Two root causes, both fixed
([#708](https://github.com/alchemy-run/alchemy-effect/pull/708)):

- **Wrangler-parity defaults** — `maxInstances` defaulted to `1`,
serializing every Durable Object through one container slot. Now
`maxInstances: 20`, scale-from-zero, and `instanceType: "lite"`
when no custom limits are set, matching wrangler.
- **Readiness polling** — probes had no per-probe timeout, so a
not-yet-listening port could hang for minutes. The loop now
mirrors `@cloudflare/containers` exactly.

Result: 100/100 cold starts, on par with wrangler. And a container
that stops or crashes is now transparently restarted on the next
request, while a crash-looping container fails fast instead of
burning the readiness budget
([#711](https://github.com/alchemy-run/alchemy-effect/pull/711)).
Docs: [Containers](/cloudflare/compute/containers).

## Effectful compute on ECS and EC2

The `ServerHost` + `{ fetch }` pattern now works end to end on
`AWS.ECS.Task`
([#713](https://github.com/alchemy-run/alchemy-effect/pull/713)):
the container entry bundles a Bun HTTP server, ships every chunk
into the image, and builds for the architecture the task declares
— verified by a smoke test that deploys a real Fargate service
behind an ALB.

The hosted `AWS.EC2.Instance` serves HTTP the same way, with a
reboot-safe systemd unit that self-heals transient boot failures
([#714](https://github.com/alchemy-run/alchemy-effect/pull/714)).
And there's a new `AWS.EC2.KeyPair` resource — the generated
private key is captured once as a `Redacted` secret:

```typescript
const keyPair = yield* AWS.EC2.KeyPair("DeployKey", { keyType: "ed25519" });
// keyPair.keyName -> AWS.EC2.Instance({ keyName })
// keyPair.privateKey -> Redacted<string>
```

## The docs got a ground-up overhaul

The website is restructured into per-provider hubs behind a
horizontal tab bar — `Core · CLI · Cloudflare · AWS · PlanetScale ·
Neon · More ▾` — with ~100 new or reworked pages
([#721](https://github.com/alchemy-run/alchemy-effect/pull/721)):

- **Core** — Infrastructure as Code, Infrastructure as Effects,
APIs, Environments, State Store, Project structure, Testing.
- **CLI** — every command documented, including the first-ever
docs for `alchemy unsafe nuke` and adopting resources.
- **Cloudflare / AWS hubs** — setup, five-part tutorials, block
pages and guides grouped by role (Compute, Frontend, APIs, Data,
Messaging, AI, …).
- Every page written against source, tests, and fixtures; every
moved URL 301s.

Start at [the docs](/) and pick your provider.

## Also in this release

- **`--yes` is fully non-interactive**
([#728](https://github.com/alchemy-run/alchemy-effect/pull/728)) —
`alchemy deploy --yes` now auto-accepts the Cloudflare state
store upgrade and deploy prompts instead of hanging on a non-TTY,
so CI needs no workarounds.
- **Partial state-store deploys are detected and recovered**
([#700](https://github.com/alchemy-run/alchemy-effect/pull/700)) —
the store health check now verifies a real store is serving, not
just that a pre-create stub exists.
- **`Command.Build` memo includes command + env**
([#738](https://github.com/alchemy-run/alchemy-effect/pull/738)) —
two `StaticSite` builds differing only in env (per-stage
`EXPO_PUBLIC_*`, API ids) no longer reuse each other's output.
- **Retained resources report as `retained`**
([#739](https://github.com/alchemy-run/alchemy-effect/pull/739)) —
destroy no longer lists `RemovalPolicy: "retain"` resources as
deleted. Thanks **bjorntechTobbe**!
- **The CLI works on Windows**
([#696](https://github.com/alchemy-run/alchemy-effect/pull/696)) —
the stack entry loads via a `file://` URL. Thanks **d3lay**!
- **Durable Object classes created outside alchemy adopt cleanly**
([#495](https://github.com/alchemy-run/alchemy-effect/pull/495)) —
class migrations fall back to matching the observed binding, so
adopting a wrangler/dashboard Worker reuses its DO classes
instead of failing to re-create them.
- **Access Application survives state loss**
([#742](https://github.com/alchemy-run/alchemy-effect/pull/742)) —
`read` falls back to a domain scan and gates takeover behind
`--adopt`, instead of blindly creating a duplicate app with a
fresh `aud`. Thanks **Andy Jefferson**!
- **Pooled connection origins** — Neon `Project`/`Branch`
([#718](https://github.com/alchemy-run/alchemy-effect/pull/718))
and PlanetScale `PostgresRole`
([#717](https://github.com/alchemy-run/alchemy-effect/pull/717))
expose `pooledOrigin`, and PlanetScale branch replica intent
persists so `replicas: 0` converges
([#719](https://github.com/alchemy-run/alchemy-effect/pull/719)).
Thanks **Alex**!
- **AWS env-auth fixes** — `Region` is provided to STS during login
([#709](https://github.com/alchemy-run/alchemy-effect/pull/709))
and the `Region`/`AWSEnvironment` layer cycle in the account-id
lookup is broken
([#710](https://github.com/alchemy-run/alchemy-effect/pull/710)).

## Where to go next

- [Docker](/docker)
- [MicroVMs](/aws/compute/microvms)
- [Workers for Platforms](/cloudflare/compute/workers-for-platforms)
- [Workflows](/cloudflare/compute/workflows)
- [Benchmarking Cloudflare Containers vs AWS MicroVMs](/blog/2026-07-01-microvm-cold-starts)
- [CHANGELOG](https://github.com/alchemy-run/alchemy-effect/blob/main/CHANGELOG.md#v200-beta60)
- [Compare v2.0.0-beta.59 → v2.0.0-beta.60](https://github.com/alchemy-run/alchemy-effect/compare/v2.0.0-beta.59...v2.0.0-beta.60)
Loading
Loading