Define your apps in one file. Kustron handles the rest: local cluster, registry, build, deploy. Your kubectl context is never touched.
npm install -g kustron && kustron doctor
One kustron-env.yaml, one command → a CRUD API over a
Redis-compatible KV store built from source → live rebuild on an
edit → a Helm-charted RabbitMQ + order stream → a public GitHub repo
deployed as-is → clean
env destroy. Hover the video for the full-screen button,
or double-click it.
Kustron provisions a local container-native cluster with k3d under the hood — you never touch it. You define what to run in one file; it builds, deploys, and watches.
Create a kustron-env.yaml in your project folder,
pre-filled with your app name.
Set ports, add more apps, configure env vars. Or just set the port and move on.
One command spins up the cluster, builds images, and deploys everything.
Add apps, change config, redeploy. The file is the source of truth.
Six situations where the environment is the whole job.
Frontend, API, database, cache, workers — everything running
together and reachable by name. Each app can also get its own
namespace with a one-line namespace: override.
env watch auto-redeploys on every save.
The kustron-env.yaml is the environment
documentation. Clone the repo, run env up, and you're
productive in minutes instead of hours.
The same file gives you an identical stack on your laptop, a teammate's machine, or a $6/month cloud VM. No "works on my machine."
Test Helm charts, private registry auth, deploy ordering with
dependsOn, HPA autoscaling, and namespace isolation
locally.
Spin up an isolated stack for a spike, a customer demo, or
integration testing. env destroy when done and
nothing lingers.
Kustron never calls kubectl config use-context. Every
command uses --context=k3d-<clusterName>, so
your production clusters stay untouched.
Apps find each other by name. Exposed apps are reachable at
localhost:<nodePort>.
config:
namespace: kustron-env # default namespace; each app can override with `namespace:`
apps:
# Build from local source or git repo
- name: api
source: ./services/api # or: git@github.com:org/repo.git
port: 3000
exposed: true # reachable at localhost:<nodePort>
ha: true # min 2 replicas, autoscales to 5
env:
NODE_ENV: production
DB_HOST: postgres # resolves to the postgres service by name
# Run an existing container image
- name: postgres
image: postgres:15
port: 5432
env:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
# Deploy a Helm chart
- name: prometheus
helm:
chart: kube-prometheus-stack
repo: https://prometheus-community.github.io/helm-charts
version: "45.0.0"
values:
grafana:
enabled: true
Start inside a source repo with a Dockerfile. Add a local DynamoDB, an S3-compatible store, and a cache, then bring it all up.
cd my-api # your repo, with a Dockerfile
kustron env init # creates kustron-env.yaml
kustron apps add --name local-ddb --image amazon/dynamodb-local:latest --port 8000 --healthcheck tcp
kustron apps add --name local-s3 --image luofuxiang/local-s3 --port 80
kustron apps add --name kivo --image ghcr.io/itsmunim/kivo:v1.5.0 --port 6379 --healthcheck tcp
kustron env up
Your app now talks to
local-ddb:8000,
local-s3:80
and
kivo:6379
by name. The cache is
kivo, our Redis-compatible in-memory store: same protocol, same port, so
it drops in where you'd use redis. Prefer the real thing? Swap in
redis:7, nothing else changes.
Every app lands with a service, so apps reach each other at
http://<name>:<port>. Set namespace: per app to isolate any of them.
Point to a folder. Kustron uses your Dockerfile if it exists, or Railpack to containerize automatically.
Provide a git SSH URL. Kustron clones it, builds it, and deploys it. SSH access must already be set up.
Use any image from Docker Hub or any registry. Perfect for databases and third-party services.
Install any Helm chart into your environment. Pass values directly from the yaml file.
| env | |
kustron env init
|
Create a kustron-env.yaml in the current folder,
pre-filled with the folder name as the app.
|
kustron env up
|
Bring up the cluster and deploy all apps from
kustron-env.yaml. Idempotent, safe to re-run.
|
kustron env reload
|
Stop all apps and bring them back up. Run this after changing
kustron-env.yaml. The cluster itself is not
destroyed.
|
kustron env watch
|
Watch local source directories and kustron-env.yaml,
auto-redeploy on changes.
|
kustron env stop
|
Stop all apps (scale to 0, uninstall helm charts) without
destroying the cluster. Fast to restart with
env up.
|
kustron env show-spec
|
Pretty-print the full kustron-env.yaml schema with
annotations.
|
kustron env status
|
Show the cluster and every app's state (Running, image pull failed, crash loop) in one table. |
kustron env down
|
Deprecated. Destroys everything. Use
env stop to pause, or env destroy to
explicitly tear down.
|
| teardown | |
kustron env destroy
[--yes]
|
Tear it all down: deletes the k3d cluster (and all data in
it), the kubeconfig context entry, and the local state file.
Confirmation prompt unless --yes is passed.
|
| apps | |
kustron apps add
[flags]
|
Add an app entry to kustron-env.yaml
(--name, --source/--image/--helm-chart,
--port, --env…). Then run
kustron env reload to apply.
|
kustron apps remove
<name>
|
Remove an app entry from kustron-env.yaml. Then
run kustron env reload to apply.
|
kustron app stop
<name>
|
Stop a single app without affecting the rest of the environment. |
kustron app start
<name>
|
Start a single app that was previously stopped. |
kustron app logs
<name>
[-f]
[-t N]
|
Stream logs for a single app. -f to follow,
-t N for the last N lines.
|
kustron app exec
<name>
[command...]
|
Run a command inside a running app container. Defaults to
sh if no command given.
|
kustron app forward
<name>
<localPort>
[remotePort]
|
Forward a local port to an app. Useful for services that are not exposed via NodePort. |
| container registry | |
kustron registry login
<server>
|
Log in to a container registry (docker/podman) so private images can be pulled and pushed. |
kustron registry prune
|
Remove unused images from the local registry to reclaim disk space. |
| doctor | |
kustron doctor
|
Check that the runtime dependencies (container runtime, k3d, kubectl, railpack, helm, git) are installed and the container daemon is reachable. Exits non-zero if anything required is missing. |
Kustron tells you exactly which of these are missing and how to get them: run kustron doctor to check, or let the install script set everything up for you.
Recommended: OrbStack over Docker Desktop. OrbStack starts in ~2 seconds (vs 30+), uses a fraction of the memory, and has native Apple Silicon support. orbstack.dev →
Or let the install script do it. It sets up the
container runtime, k3d, kubectl, railpack (plus optionally Helm
and git) — asking y/n before each step, or pass
-y
to accept all — then installs kustron from npm.
curl -fsSL https://raw.githubusercontent.com/itsmunim/kustron/master/install.sh | bash
Kustron is a Node CLI installed from npm (Node >= 18).
brew install node
or nvm.
OrbStack (recommended on macOS) · Podman (any platform) · or Docker Desktop. Kustron auto-detects whichever you have.
brew install k3d
·
k3d.io/installation
brew install kubectl
Only needed when deploying source without a Dockerfile. railpack.io
Only needed when deploying Helm chart apps.
brew install helm
Only needed when deploying from a git SSH URL. Usually pre-installed.
Not just for local dev. Run it on any cloud VM and your stack, APIs, frontends, databases, is on the real internet. No cluster management.
Any Linux instance works: EC2, DigitalOcean Droplet, Hetzner Cloud, Linode. Even a $6/month box is enough for a real multi-service stack.
Install the container runtime (Docker or podman), k3d, kubectl, and kustron. Add your GitHub (or GitLab) SSH key so kustron can pull private repos directly on the instance.
kustron-env.yaml
List your apps with
exposed: true
for anything that needs to be public. Kustron maps each port
to the VM's network interface.
One command: cluster, registry, images, deployments, all at once.
Allow the exposed ports in your security group (AWS) or
firewall rules. That's it, your stack is live at
<vm-ip>:<port>.
postgres
and
redis
stay internal. Never expose them.
OrbStack (macOS, recommended):
brew install --cask orbstack, open it once, done. Kustron detects it automatically.
Podman (any platform):
brew install podman
(macOS) or your package manager (Linux), then
podman machine init --rootful --cpus 4 --memory 4096
and
podman machine start. The kustron installer does all of this for you and checks the
daemon is responding.
Docker Desktop works too, but it's heavy with k3d. See the next question.
Docker Desktop runs Linux in a VM, and k3d runs its own cluster inside that VM. Two layers of virtualization means the k3d containers keep chewing CPU even when idle, plus several GB of RAM. OrbStack and Podman don't stack a second VM on top, which is why k3d is much happier on both.
Podman reserves
bridge
as a network mode keyword, so a network can't be named that.
Kustron used to try creating one before starting the cluster,
which is exactly where this error came from. k3d handles
networking itself (it auto-creates a
k3d-<cluster>
network on podman), and current kustron versions just let it.
Update kustron with
npm update -g kustron
and run
kustron env up.
Railpack used to ship on npm, so
npm i -g railpack
broke for anyone pointed at a private registry. It's not on npm
anymore: the installer downloads the prebuilt binary straight from
GitHub releases. No npm, no brew, no package manager involved.
Building an app that pulls private npm deps (without a
Dockerfile)? Keep your
.npmrc
auth or
NPM_TOKEN
env var in the app's build environment so railpack can
authenticate.
Kustron probes ports with an exclusive bind, so services that are
genuinely listening there (macOS AirPlay is a classic on port
5000) are honored and the registry picks the next free port. You
can also set a specific port via
config.registryPort
in
kustron-env.yaml.
Once created, the port is stable: kustron reads it back from the
running registry container every run, so image pushes can't end up
on a stale port. The registry itself is cluster-scoped —
kustron-registry
for the default cluster,
<clusterName>-registry
otherwise — so multiple local clusters don't fight over one
registry.
A k3d cluster wants around 4GB in the podman VM. On macOS:
podman machine init --rootful --cpus 4 --memory 4096
for a new machine, or
podman machine set --memory 4096
+ restart for an existing one.
No. Kustron never calls
kubectl config use-context. Every kubectl and helm command includes
--context=k3d-<clusterName>
(or
--kube-context
for helm), so your global kubectl context is never touched. You
can safely run
kustron env up
while working with production clusters in other terminals.