Tiny zero-dependency CLI for keeping Kubernetes kubectl port-forward sessions alive from a repo-local config.
One line — downloads the prebuilt standalone binary, no bun needed:
curl -fsSL https://raw.githubusercontent.com/edenlabllc/portforward/main/get.sh | shThis installs portforward to ~/.local/bin. Override with PORTFORWARD_BIN_DIR=/usr/local/bin, or pin a version with PORTFORWARD_VERSION=v1.2.3.
kubectl, lsof, and pkill must be available at runtime.
portforward upgrade # fetch and install the latest release in place
portforward version # show installed versionupgrade replaces the running binary with the latest release for your platform. Re-running the curl … | sh line does the same thing.
With bun installed, build and install a binary locally:
git clone https://github.com/edenlabllc/portforward port-forward
cd port-forward
./install.sh # compiles dist/portforward and installs it
# or just: bun run build # produces dist/portforward
bun test # run the unit testsNo
bun installis required — the project has no runtime dependencies.
Push a tag and GitHub Actions cross-compiles all platforms and attaches them to the Release:
git tag v1.2.3
git push origin v1.2.3Released binaries know their own repo and version, so portforward upgrade and portforward version work out of the box.
portforward init
portforward check
portforward startstart reads the first config it finds:
portforward.yamlportforward.yml.portforward.yaml.portforward.yml.workspace.yaml
By default start runs every service in the config. Use --svc (repeatable) to run only some. The term is matched as a case-insensitive substring of the service name, so postgres matches postgres-cluster-pooler and clickhouse matches both clickhouse-http and clickhouse-native:
portforward start --svc minio --svc postgresAn unknown term fails fast and lists the available services.
name: local-dev
services:
api:
namespace: default
localPort: 8080
remotePort: 8080
postgres:
namespace: default
localPort: 5432
remotePort: 5432If pod is omitted, the service key is used as the pod lookup term. Pod lookup uses exact match, then prefix match, then substring match.
You can also be explicit:
services:
api:
namespace: default
pod: api-deployment
localPort: 8080
remotePort: 8080Or forward to a Kubernetes Service resource:
services:
api:
namespace: default
service: api
localPort: 8080
remotePort: 8080start checks local ports with lsof, reclaims stale kubectl port-forward processes for the same local port, and reconnects with backoff when a connection drops.