Ship the app.
Not the runtime.

Your application is the workload.
The runtime is infrastructure.

Manage language runtimes at the infrastructure level, like the OS or Kubernetes—not inside every application image. Like a Dockerfile minus the base image, package your app code, dependencies and launch metadata; Brewlet supplies an approved, node-resident runtime at launch.

For application developers · For platform teams

Application workloadapplication@sha256:…
Your applicationCode + dependencies
launch.jsonExplicit process + platforms
Runtime infrastructureRuntimeImage / python-3.13
Approved runtime rootInterpreter or VM + userland

Brewlet at Devoxx Belgium 2026

Bruno Borges introduces Brewlet and explores a WebAssembly-inspired way to run Java workloads on Kubernetes.

Bruno Borges presenting Brewlet at Devoxx Belgium 2026

Put the runtime back
in infrastructure.

Like the OS or Kubernetes, the runtime is provisioned and updated as infrastructure—not rebuilt into each application image.

A conventional application image

The application image references its runtime and userland. Updating that base normally means rebuilding or recomposing the application image, then rolling it out.

With Brewlet

The workload ships code, dependencies and a launch descriptor. Infrastructure supplies and updates the approved runtime. New containers use the updated runtime without rebuilding application bytes.

Both approaches cache unchanged layers. Shared runtime files do not mean shared application processes or heaps. Runtime rotation does not patch libraries bundled in your application. When to use Brewlet—and when not to.

Built around Kubernetes.
Not another workload API.

  1. Approve the runtime

    A cluster-scoped RuntimeImage binds a stable ID to a digest-pinned image and non-root numeric defaults. A NodeProfile offers it on selected pools.

  2. Publish the application

    Package explicit app/dependency layers under /app, a versioned launch.json and declared OCI platforms. The CLI never guesses the language.

  3. Select, schedule, compose

    Use a normal Deployment with runtimeClassName: brewlet and one runtime ID. The shim validates the artifact, leases a runtime generation and delegates to runc.

How the pieces fit

Brewlet architecture: containerd pulls the application artifact, infrastructure provisions the runtime generation, and the shim validates, leases and composes them before delegating to runc. Kubernetes schedules ordinary workloads; the operator reconciles runtime infrastructure.
The application is the workload; the runtime is infrastructure. Containerd pulls the application image. Only the fenced provisioner installs runtime roots; the shim uses verified local content. Open full-size diagram · Download editable source
Runtimes loaded when needed.

Choose Eager for a warm pool, or OnDemand to validate baseline readiness before fetching runtime roots. A bounded first-use wait lets kubelet retry installation without running unvalidated application code.

Explore runtime inventory

Describe the process.
Ship only your app.

launch.json
{
  "schemaVersion": 1,
  "process": {
    "entrypoint": ["python3"],
    "args": ["/app/src/main.py"],
    "workingDir": "/app"
  }
}
Package and publish
brewlet build registry.example.com/apps/api:v2 \
  --platform linux/arm64 \
  --launch launch.json \
  --layer app=./src:/app/src
brewlet push registry.example.com/apps/api:v2

This example has no third-party dependencies. Add explicit dependency layers and lookup paths when your application needs them.

Examples are templates, not a live terminal. Use your registry and actual supported platforms. Java project intelligence is available in the optional Maven producer; it does not select a pod runtime or generate workloads.

Your workload still looks like Kubernetes.

Platform teams load an approved runtime into a node pool with a NodeProfile. Application teams select that runtime ID and keep Services, probes, resources, volumes and normal rollout strategies. Each application container in a Brewlet Pod uses the same runtime ID, whatever the language.

Read the application contract
Cluster setup · RuntimeImage + NodeProfile
apiVersion: node.brewlet.sh/v1alpha1
kind: RuntimeImage
metadata:
  name: app-runtime
spec:
  source:
    image: registry.example.com/golden/runtime@sha256:<digest>
  user:
    uid: 65532
    gid: 65532
---
apiVersion: node.brewlet.sh/v1alpha1
kind: NodeProfile
metadata:
  name: application-pool
spec:
  nodePool:
    key: brewlet.example.com/pool
    names: [applications]
  runtimeImages:
    - id: app-runtime
      install: OnDemand

The RuntimeImage approves a digest-pinned runtime image (any language) as app-runtime. The NodeProfile loads that ID onto the pool.

Application · Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  selector:
    matchLabels: {app: api}
  template:
    metadata:
      labels: {app: api}
      annotations:
        brewlet.sh/runtime-image: app-runtime
    spec:
      runtimeClassName: brewlet
      containers:
        - name: api
          image: registry.example.com/apps/api@sha256:<digest>

Patch the runtime.
Keep the application.

Rotate the digest behind a stable runtime ID. New containers resolve the approved current generation. Existing containers keep a durable lease on the generation they started with.

Optional, opt-in workload restarts use an inventory-epoch and minimum-generation barrier. A successful template patch is not a completed remediation.

Understand rotation and cleanup
Explicit authority
Short-lived local authorization is renewed only after fresh inventory and ownership checks.
Safe lifetime
Task, Exec and mount references protect roots and shared cache entries. Uncertainty blocks collection.
Honest boundaries
Non-root processes, runtime-owned PATH and read-only packaged content. runc isolation, not a new security boundary.

Start with the source.
Evaluate in isolation.

The implementation has verified local implementation acceptance. It is not a published stable release or a claim of cloud-provider autoscaling certification.

Run a small HTTP service on a disposable node, inspect its actual runtime binding, rotate the source without rebuilding the application, and clean up normally. See the demonstration sequence.

Build Brewlet
git clone --branch main \
  https://github.com/microsoft/brewlet.git
cd brewlet
make build

Brewlet at a glance.

Install Brewlet on a cluster, ship an application, and rotate its runtime. Keep the essential commands, deployment workflows, and operational reminders close at hand.

One-page A3 landscape PDF for your desk or team room. The online reference includes complete recipes and links to the detailed guides.

Brewlet infographic with an application-plus-runtime diagram and three columns: install and configure, build and deploy, and operate and rotate.
From cluster setup to historical runtime bindings, on one printable page.

A few important
distinctions.

Can I bring my own custom runtimes?

Yes. Use a compatible upstream image unchanged, including distroless images, or build your own OCI runtime image. Approve its digest as a RuntimeImage, offer it through a NodeProfile, and select its ID in your workloads. The runtime image contract requires validated platforms and non-root numeric identities, not a shell or an account named app. Use explicit executable paths when the runtime has no PATH.

Can I run WebAssembly?

Yes, through an approved Linux Wasmtime or Spin host on the existing runc path. The qualified examples cover a WASIp1 command and a pinned Spin SDK HTTP component on arm64, with explicit guest access and workload-local caches. This does not accept native SpinKube artifacts or install a runwasi backend. Explore the Wasm examples and their scope.

Do existing applications switch runtime in place?

No. Running processes keep their leased generation. New containers use current. An optional restart coordinator can patch opted-in native controllers; it does not hot-swap a VM, kill pods directly or override rollout strategies.

Do I still need an application image?

Yes. The application is a standard, digest-addressed OCI image with application layers, optional dependency layers and a final launch layer. It omits the platform runtime root; it is not an image-free deployment.

Does sharing the runtime mean sharing processes?

No. Runtime files are shared read-only on the node. Every workload has its own process, resources and container isolation. There is no claim of automatic heap sharing or benchmarked memory savings.

How do CPU and memory limits work?

Ordinary Kubernetes requests, limits and runc cgroups apply to each workload. RuntimeClass overhead is additional shim/staging capacity, not a language heap budget. Brewlet injects no tuning flags. Plan resources and lifecycle behavior.

Can I use mixed-architecture pools?

Yes, when the runtime and application bytes support the selected platforms and native scheduling constraints place them correctly. An OCI index is not a scheduler instruction. Current local physical qualification is arm64. Read the platform boundaries.

How do I debug a runtime without a shell?

Use application health endpoints or explicit diagnostic executables already supplied by the application/runtime. Brewlet does not add a shell or infer a probe command. Follow the failure guide.

What supply-chain guarantees are included?

Artifact integrity, strict execution contracts and approved runtime digests are distinct from signing policy. Dependency layer sets support provenance, but do not automatically attest every final application. Review the trust boundaries.

Can I use ordinary images and run as root?

Ordinary workloads still use the stock Kubernetes runtime. Within a Brewlet Pod, every application container must use a v1 artifact and run non-root without privilege escalation. Only the infrastructure sandbox bypasses application processing.

Ship your application.
Let infrastructure supply the runtime.

Explore the documentation