Hello, Jae Wook Kim here. In my last post, we talked about winning the “Inner Loop”—using Dev Containers to standardize your immediate coding environment.
But as your project scales from a single repository to a cluster of microservices, you hit a new wall of friction. This is the Outer Loop: the ecosystem of services, databases, and dependencies your code lives in.
If you are still waiting 5 minutes for a CI build to see if your code works in a “real” cluster, you are losing. Today, we’re building a “Golden Path” for the Outer Loop using Tilt, OrbStack, and ctlptl.
The Stack: Why OrbStack + Tilt?
If you are on a Mac, you’ve likely felt the weight of traditional Docker desktops. They are resource-hungry and can turn your laptop into a space heater.
OrbStack (orbstack.dev) is the antidote. It’s a lightweight, native replacement for Docker Desktop that boots in seconds and uses significantly less memory. But more importantly for DevEx, it makes local Kubernetes feel “free.”
Tilt (tilt.dev) is the orchestration layer. It sits on top of your cluster and watches your files. When you save a file, it doesn’t just rebuild an image; it incrementally syncs that change into the running container.
Setup: Standardizing the Cluster with ctlptl
In a high-performing DevEx culture, we don’t ask developers to “Check a box in a GUI.” We codify the setup.
We use ctlptl (pronounced “cattle patrol”) to “stamp” our local development clusters. Instead of manual configuration, we provide a ctlptl.yaml in the repository root:
# ctlptl.yaml
apiVersion: ctlptl.dev/v1alpha1
kind: Cluster
name: orbstack-cluster
product: kind
registry: orbstack-registry
---
apiVersion: ctlptl.dev/v1alpha1
kind: Registry
name: orbstack-registry
port: 5005
With one command—ctlptl apply -f ctlptl.yaml—every developer on the team gets the exact same Kind cluster running on the OrbStack engine, complete with a local registry for instant image pushing.
Hands-on: The “Aha!” Moment with the Tiltfile
Let’s look at a real example in our sample_project. We have a simple TypeScript Express API that we want to run in our cluster.
Instead of a complex script of kubectl apply commands, we use a Tiltfile:
# Tiltfile
docker_build(
'sample-app-image',
'./app',
dockerfile='./app/Dockerfile',
live_update=[
sync('./app/src', '/usr/src/app/src'),
sync('./app/package.json', '/usr/src/app/package.json'),
run('npm install', trigger=['./app/package.json']),
]
)
k8s_yaml(['./k8s/deployment.yaml', './k8s/service.yaml'])
k8s_resource('sample-app', port_forward=8080)
Magic Feature: live_update
The core of DevEx is feedback loops.
Notice the live_update block. When you edit a file in /src, Tilt doesn’t rebuild the Docker image. It simply copies the file into the existing container. Because we’re using a tool like ts-node-dev inside the container, the app reloads instantly.
You get the “save-and-refresh” experience of local development, but your code is actually running inside a Kubernetes pod in a production-like environment.
Removing the “Re-deploy” Friction
Why does this matter? Because friction is cumulative.
If a fresh deploy takes 3 minutes, you’ll stop checking your work frequently. You’ll batch changes, leading to harder-to-debug errors. By reducing that loop to under 1 second, you enable a flow state where developers can experiment and iterate without context switching.
Summary of the “Golden Path” for 2026:
- OrbStack: The engine (Fast, light).
- ctlptl: The “Stamper” (Codified, reproducible).
- Tilt: The Orchestrator (Live updates, visibility).
Conclusion
Developer Experience isn’t about making things “easy”; it’s about making them fast and predictable. By standardizing your Outer Loop with Tilt and OrbStack, you remove the “it works on my machine” excuses and the “waiting for CI” coffee breaks.
The best infrastructure is the kind you don’t have to think about.
If you want to see the full code for this setup, check out the sample_project on my GitHub.
Thanks for reading! Feel free to reach out on LinkedIn if you’d like to discuss how to optimize DevEx for your engineering team.
Have a great day!
Comments