Kiln
v2.1 · pnpm + Bazel + Nx

Build only what changed. Cache like you mean it.

Kiln watches your task graph, fingerprints inputs, and skips packages that didn't change since the last green main. The average PR in a 47-package monorepo touches 3 — so 44 should be a cache hit.

$ pnpm dlx kiln init
pipeline · PR #4128 · 3 of 47 packages affected
running · 1m 41s commit 8f2a1c
install cache hit lint skipped 44 typecheck skipped 44 unit 3 of 47 · run e2e queued build 3 of 47 · run container queued · 3 oci deploy preview install check test & build artifact deploy
cached running queued
acme/web · 14d
live
Avg build time
2m 41s
−68% / 30d
Cache hit ratio
89.4 %
+8.2pp / 30d
Parallel jobs P95
18
runner pool 32
Cost per build
$0.0064
−$0.018 / 30d
Build minutes / day 14d
runners: us-east + eu-west cache 4.8 TB
Building monorepos in production at
Cargo SPOOL FOLIO Beacon Nimbus Labs mercury/build Forecast Engineering Linnea Platform Cargo SPOOL FOLIO Beacon Nimbus Labs mercury/build Forecast Engineering Linnea Platform
Capabilities

A graph-aware build system that finally feels native.

Kiln reads your pnpm-workspace.yaml, your Bazel BUILD files, or your Nx project graph — and turns it into a fingerprinted DAG. Cache anywhere. Run anywhere.

Pipeline as code

Tasks. Inputs. Outputs. That's the whole config.

A task declares what it reads and what it writes. Kiln fingerprints the input set, looks up the cache, and either skips the task or runs it on the next free runner.

kiln.yaml v2 · cache: remote
# task graph for acme/web
tasks:
  build:
    depends_on: [typecheck, lint]
    inputs:
      - "src/**/*.{ts,tsx}"
      - "package.json"
      - "!**/*.test.ts"
    outputs:
      - ".next/standalone"
      - ".next/static"
    command: pnpm next build
    cache: remote

  container:
    depends_on: [build]
    command: docker buildx --cache-to=kiln
    runner: "oci-builder-xl"
Cache hit ratio

30% on day one. 89% by week four.

Remote cache, content-addressed by input fingerprint, scoped per branch and per package.

day 1day 7day 14day 21day 28
Parallel runner timeline

32 jobs in flight. None of them rebuilding the world.

A gantt of the current build. Bars colored by package, grayed if pulled from cache.

@acme/web
48s
@acme/ui
cache
@acme/api
24s
@acme/sdk
cache
@acme/cli
18s
@acme/db
cache
Affected detector

3 of 47 packages changed.

Computed from the dependency graph + file fingerprints in the diff. We never run downstream what wasn't actually touched.

@acme/webchanged
@acme/uichanged
@acme/checkouttouch
+ 44 packagesskipped
Deploy approvals

Promote a build. Not a re-build.

Promotions reuse the exact OCI digest that passed CI. No "deploy will recompile" surprises.

staging
8f2a1c 2m
canary 5%
3c1b80 8m
production
71a4e2 1h ago
acme/web · 47 pkgs
Avg PR build
2m 41s
↘ −5m 38s / 30d
Packages skipped
44 / 47
94% per PR avg
Cache writes / day
12,408
348 GB total
Task graph · this PR 3 of 47 to run
src build test app
Smart task graph

Skip 39 packages. With proof.

Kiln walks your dependency graph from the diff, fingerprints the inputs of every reachable task, and only schedules the work that actually changed. The graph is signed — you can prove which packages a release contains.

  • Input fingerprints include sourcemap-resolved deps — refactors don't bust the cache.
  • Remote cache speaks the gRPC RBE protocol so Bazel users get instant adoption.
  • Spawn an isolated preview environment per package, not per PR.
  • SLSA-3 attestations on every artifact; signed by your org key, not ours.
Read the task-graph guide
Pricing

Pay for the builds you ran. Not the ones we skipped.

Cache hits are free. We bill per minute of actual compute, plus a flat platform fee.

Hobby

free forever
$0
/ month

For OSS and weekend projects.

  • 100 build mins / mo
  • 1 GB remote cache
  • Shared runners · 2 vCPU
  • Community Slack
Start free
Most popular

Pro

per seat
$49
/ seat · month · annual

For teams shipping every weekday.

  • 5,000 build mins / mo · pooled
  • 100 GB remote cache · global
  • Runners up to 16 vCPU / 64 GB
  • SLSA-3 attestations
  • Preview envs · 14d TTL
Start 14-day trial

Enterprise

self-hosted
$299
/ month base · usage on top

For platform teams with their own runner farm.

  • Unlimited build mins
  • BYO runners · 0 egress
  • SAML SSO · SCIM · audit log
  • SOC 2 · solution architect
Talk to sales
Customers

Platform & DX teams who got their afternoons back last quarter.

"We had an 18-minute build that the team had stopped trying to fix. Kiln got it to 2m 41s in the first week, just by being honest about which packages a PR actually touched."
MT
Marcus Tobin
Platform Lead · Forecast
"Cache hit ratio sat at 30% under our old setup. After moving to Kiln's RBE-compatible cache it's been 89% for the last 28 days, and our CI bill dropped 64%."
YA
Yusuf Abara
CTO · Mercury
"Migration from Nx Cloud took an afternoon. The promotion model — same OCI digest from canary to prod — is the part our SRE team actually cared about."
PA
Priya Anand
Staff Engineer · Linnea
FAQ

Frequently asked, honestly answered.

Most of our team is ex-Bazel and ex-Buck. If you have a deeper question, ping [email protected].

How does it compare to Turborepo or Nx Cloud?+

Turbo's caching is filename-shaped — you tell it "if these files change, rerun this task." Kiln resolves the actual import graph, so renaming a file or moving an export still hits the cache. Versus Nx Cloud: Kiln's cache speaks Bazel's gRPC RBE protocol, which means you can also bring Bazel rules and our cache will hit them. Most teams migrating tell us they keep Turbo for hot reload locally and run Kiln in CI.

Can I bring my own self-hosted runners?+

Yes. Self-hosted runners are a first-class deployment target. The runner is a single static binary that registers with our control plane over outbound HTTPS — no inbound port. Most customers run a Karpenter-managed pool on EC2 spot, with auto-scaling driven by Kiln queue depth. Egress between your runners and our cache is free.

What's the protocol for the remote cache (HTTP/gRPC)?+

Both. The native protocol is gRPC Remote Execution v2 (the Bazel RBE wire format) over HTTP/2 with mTLS. We also expose a HTTP/1.1 fallback for environments without gRPC support — tested with Turborepo, Nx, and a homegrown CLI. Content addressing is SHA-256, max blob 4 GB, no compression on the wire (we rely on TLS-layer compression where available).

Does it support Bazel rules_oci out of the box?+

Yes — both rules_oci and rules_docker. The OCI artifact lands in our content-addressed store, which means a downstream oci_push action is a pointer move rather than a re-pack. Container builds that used to take 7 minutes drop to about 12 seconds end-to-end once cached.

How do you handle secret injection during builds?+

Secrets are scoped per task in kiln.yaml, fetched from Vault / AWS Secrets Manager / GCP Secret Manager at runner startup, and exposed via tmpfs file paths — never as env vars unless you explicitly opt in. Secret-bearing tasks are excluded from the remote cache by default so a malicious PR can't exfiltrate them via a poisoned cache key.

89% cache hit · 30 days

Trim the build. Keep the speed.

Connect your monorepo in 5 minutes. The free tier covers 100 minutes a month — enough to feel the difference on day one.