WARNING: Deployah is experimental and under active development.
Deployah is a CLI tool that makes deploying applications effortless by leveraging Helm—no Kubernetes or Helm expertise required.
brew install deployah-dev/tap/deployahIf you have Nix installed:
# Run directly without installation
nix run github:deployah-dev/deployah
# Or add to your flake.nix
inputs.deployah.url = "github:deployah-dev/deployah";go install deployah.dev/deployah@latestThe flake is the canonical dev and CI interface. With direnv (.envrc uses use flake), tools load automatically when you enter the repo.
nix developnix run .#fmt # format Go (gofumpt + gci)
nix run .#lint # golangci-lint
nix run .#lint-md # markdownlint
nix run .#tidy # go mod tidyUnit and integration tests are split by build tag. Plain go test ./... skips integration tests.
nix run .#test-unit # unit tests with race detector
nix run .#test-integration # scenario tests in internal/testingCoverage profiles are written to coverage-unit.out and coverage-integration.out.
nix build # build the deployah binary
nix run . -- --help # run without installingnix flake check # runs pre-commit hooks (lint, markdownlint, go-mod-tidy, nixfmt)Format Nix files with nix fmt.
Before using Deployah, ensure you have:
- Kubernetes cluster access (local or remote)
For local development, you can use kind or minikube.
Deployah's local cluster runs Kind (Kubernetes in Docker) with cloud-provider-kind for LoadBalancer, Ingress, and Gateway API support.
On both Linux and macOS, services are accessible via localhost through Docker
port mapping. The networking chain is:
localhost:<port>
-> Docker port mapping
-> Envoy gateway container
-> Kind cluster pod
On macOS (and other Docker-in-VM setups like Lima, Colima, Docker Desktop, OrbStack), there is an additional transparent layer:
macOS localhost:<port>
-> VM port forwarding (automatic)
-> Docker port mapping
-> Envoy gateway container
-> Kind cluster pod
The VM port forwarding is handled automatically by your Docker runtime and requires no configuration.
Note: LoadBalancer, Ingress, and Gateway API require a rootful Docker daemon. Rootless Docker cannot bind-mount the Docker socket into the
cloud-provider-kindsidecar container, which prevents it from managing LoadBalancer resources.
Run deployah cluster status to see the assigned ports and ready-to-use URLs
for all Ingress and LoadBalancer resources in the cluster.
-
Create a
deployah.yamlmanifest in your project root. -
(Optional) Add a
.envor.env.<envName>file for environment-specific variables. -
Run Deployah:
deployah deploy production
Deployah transforms your simple deployah.yaml manifest into a complete Kubernetes deployment through an 8-phase pipeline:
flowchart LR
%% Phase 1: Input Processing
subgraph phase1["🔵 Phase 1: Input Processing"]
direction TB
A["📄 YAML"] --> B["🔍 Parse"] --> C["✅ Validate"]
end
%% Phase 2: Configuration Resolution
subgraph phase2["🟣 Phase 2: Configuration Resolution"]
direction TB
D["🌍 Environment"] --> E["🔄 Variables"] --> F["⚙️ Defaults"]
end
%% Phase 3: Deployment
subgraph phase3["🟢 Phase 3: Deployment"]
direction TB
G["📊 Helm Values"] --> H["🚀 Deploy"]
end
%% Connect phases with animated edges
phase1 e1@--> phase2
phase2 e2@--> phase3
e1@{animate: true}
e2@{animate: true}
%% Enhanced styling with better colors and effects
style A fill:#e3f2fd,stroke:#1976d2,stroke-width:3px,color:#000
style B fill:#bbdefb,stroke:#1976d2,stroke-width:3px,color:#000
style C fill:#90caf9,stroke:#1976d2,stroke-width:3px,color:#000
style D fill:#f3e5f5,stroke:#7b1fa2,stroke-width:3px,color:#000
style E fill:#e1bee7,stroke:#7b1fa2,stroke-width:3px,color:#000
style F fill:#ce93d8,stroke:#7b1fa2,stroke-width:3px,color:#000
style G fill:#e8f5e8,stroke:#2e7d32,stroke-width:3px,color:#000
style H fill:#4caf50,stroke:#2e7d32,stroke-width:4px,color:#fff
%% Subgraph styling with better borders and backgrounds
style phase1 fill:#f8f9ff,stroke:#1976d2,stroke-width:3px,stroke-dasharray: 8 4
style phase2 fill:#faf5ff,stroke:#7b1fa2,stroke-width:3px,stroke-dasharray: 8 4
style phase3 fill:#f0fff0,stroke:#2e7d32,stroke-width:3px,stroke-dasharray: 8 4
%% Node styling with rounded corners and shadows
classDef pipelineNode fill-opacity:0.95,stroke-opacity:0.9,rx:8,ry:8
class A,B,C,D,E,F,G,H pipelineNode
The deployment process is organized into three logical phases:
- Parse → Read and validate your YAML manifest structure
- Validate → Check against JSON Schema for correctness and type safety
- Resolve Environment → Select the right environment configuration based on CLI arguments and manifest definitions
- Substitute Variables → Replace
${VARIABLES}with actual values using clear precedence rules - Apply Defaults → Fill in sensible defaults from schema patterns and resource presets
- Generate Helm Values → Convert to Helm-compatible format with proper resource mappings
- Deploy → Use Helm to deploy to Kubernetes with monitoring and error handling
Each phase has specific error handling and validation, ensuring deployments are safe and predictable.
-
Developer-First Experience: Prioritize simplicity and developer productivity over advanced features. Most applications follow similar deployment patterns, so Deployah provides sensible defaults and clear variable substitution.
-
Layered Validation Strategy: Multi-layer validation with JSON Schema at the core. This provides standardized validation with clear error messages, supports API versioning, and allows for both schema and business rule validation.
-
Explicit Variable Precedence: Clear, documented variable substitution hierarchy prevents confusion about which values take precedence and enables environment-specific overrides while maintaining security.
-
Schema-Driven Defaults: Extract default values from JSON Schema rather than hardcoding them. This creates a single source of truth for validation and defaults, ensuring automatic consistency.
-
Kubernetes Complexity: Eliminates the need to understand Helm charts, Kubernetes manifests, or cluster-specific configurations. Deployah handles all the underlying complexity while providing a clean interface.
-
Configuration Management: Single manifest file with environment-specific overrides, clear variable substitution, and explicit precedence rules. No more scattered configuration files or environment-specific scripts.
-
Deployment Safety: Built-in validation prevents common deployment mistakes, ensures resource specifications are reasonable, and provides clear error messages with actionable suggestions.
-
Team Consistency: Standardized deployment patterns across teams and projects, reducing onboarding time and preventing configuration drift between environments.
-
Environment Management: Explicit environment selection prevents accidental deployments to wrong environments, with clear error messages guiding users to correct usage.
Deployah uses a Helm chart library as its foundation, automatically generating the appropriate Kubernetes resources (Deployments, Services, Ingress, HPA) based on your component definitions. The tool handles all the Helm complexity while providing a clean, declarative interface.
Deployah supports multiple environments (e.g., dev, staging, prod) for flexible deployments.
You can omit the environments section for a single default environment:
components:
my-app:
image: my-image:${IMAGE}If you define more than one environment, you must specify which one to use:
environments:
- name: dev
variables:
FOO: bar
- name: prod
variables:
FOO: baz
components:
my-app:
image: my-image:${IMAGE}Selection rules:
- If
environmentsis omitted, Deployah uses a built-indefaultenvironment. - If only one environment is defined, it is used automatically.
- If multiple environments are defined, you must specify the environment argument:
deployah deploy <name>. - If you do not specify an environment argument and multiple environments exist, Deployah will show an error listing available environments.
# Deploy to production using default manifest path
deployah deploy production
# Deploy to staging with an explicit manifest path
deployah deploy staging -f ./path/to/deployah.yamlWhen substituting variables in your deployah.yaml manifest, Deployah uses the following precedence (lowest to highest):
- Environment Definition Variables:
Defined in thevariablesfield of the selected environment in your manifest. - Env File Variables:
Loaded from the resolved environment file (e.g.,.env.production). - OS Environment Variables:
From your shell, with theDPY_VAR_prefix (these override all others).
Example:
# In deployah.yaml
environments:
- name: production
variables:
APP_ENV: manifest# In .env.production
DPY_VAR_APP_ENV=envfile# In your shell
export DPY_VAR_APP_ENV=osenvThe value used for ${APP_ENV} will be osenv.
Note: In
deployah.yaml, reference variables without theDPY_VAR_prefix (e.g.,${IMAGE}).
| File | Used by | Purpose |
|---|---|---|
deployah.yaml |
Deployah | Main Deployah manifest/config |
.env / .env.<envName> |
Deployah & App | Variable substitution for both; Deployah only uses variables starting with DPY_VAR_ |
config.yaml |
Application | App-specific config, ignored by Deployah |
config.<envName>.yaml |
Application | App-specific config for named environments, ignored by Deployah |
- Deployah only reads
deployah.yamland.envfiles. - Deployah only uses variables from
.envthat start withDPY_VAR_. - Variables in
.env(or.env.<envName>) that do NOT start withDPY_VAR_are available for your application, but are ignored by Deployah. config.yamlandconfig.<envName>.yamlare ignored by Deployah (they're for your app).
- Default environment:
- Deployah uses
.envfor variable substitution (only variables starting withDPY_VAR_). - The application uses
config.yamlfor its configuration.
- Deployah uses
- Named environments:
- Deployah uses
.env.<envName>for variable substitution (e.g.,.env.production). - The application uses
config.<envName>.yamlfor its configuration.
- Deployah uses
Default:
# deployah.yaml
components:
my-app:
image: my-image:${IMAGE}# .env
DPY_VAR_IMAGE=my-image:latest
BAR=baz # For your app, ignored by Deployah# config.yaml (for your app)
someAppSetting: trueNamed (production):
# .env.production
DPY_VAR_IMAGE=my-image:prod
DPY_VAR_API_URL=https://api.example.com
APP_SECRET=supersecret # For your app, ignored by Deployah# config.production.yaml (for your app)
someAppSetting: false
apiUrl: https://api.example.com- Minimal for beginners, powerful for experts
- No accidental deployments to the wrong environment
- No magic or hidden defaults
- Easy to document and reason about
Deployah provides several commands for managing your deployments:
# Deploy to an environment
deployah deploy <environment>
# List available environments and components
deployah list
# Check deployment status
deployah status
# View application logs
deployah logs
# Validate your manifest
deployah validate
# Delete deployments
deployah delete
# Get help for any command
deployah <command> --helpError: environment "production" not foundCheck your deployah.yaml for the correct environment name, or run
deployah list to see what is available.
Error: variable ${IMAGE} not foundMake sure the variable is defined in your environment file (.env or
.env.<envName>) with the DPY_VAR_ prefix, or set it in your shell.
Error: unable to connect to Kubernetes clusterVerify your cluster is reachable with kubectl cluster-info.
Error: failed to generate Helm valuesCheck your manifest syntax and make sure all required fields are present.
Run deployah validate to find issues.
Lima's VZ driver uses a usernet-based port forwarder by default. This forwarder has a known issue with custom Docker networks like the one Kind creates, causing connections to silently fail.
To fix it, edit your Lima instance config:
limactl stop <instance>
limactl edit <instance>Make sure both settings are present at the top level of the YAML:
ssh:
overVsock: false
portForwards:
- guestIPMustBeZero: true
guestPortRange: [1, 65535]
hostIP: 127.0.0.1
- guestSocket: "/var/run/docker.sock"
hostSocket: "{{.Dir}}/sock/docker.sock"ssh.overVsock: false switches Lima to the standard SSH port forwarder.
The portForwards rule tells Lima to forward all guest ports to the host,
which is needed for the dynamically assigned Docker ports.
Then restart:
limactl start <instance>The cloud provider sidecar needs a rootful Docker daemon. Rootless Docker cannot bind-mount the Docker socket into the sidecar container.
If you use Lima, create a rootful instance:
limactl start template:docker-rootfulGateway ports are bound on all interfaces (0.0.0.0). On Linux, make sure
your firewall allows the mapped ports. On macOS, the Application Firewall
may ask for permission -- allow it when prompted.
For more details, run:
deployah --help
deployah <command> --helpDeployah uses JSON Schema for validation. The schema defines the structure and validation rules for your deployah.yaml manifest.
- Schema Version: v1-alpha.1
- Schema Location:
internal/manifest/schema/v1-alpha.1/manifest.json - Environment Schema:
internal/manifest/schema/v1-alpha.1/environments.json
For the latest schema documentation and examples, see the schema directory in the repository.