Skip to content
Docs menu / Introduction

Introduction

konfig.ts lets you describe a Kubernetes environment in TypeScript and render it to plain YAML that Argo CD can sync. It ships as a set of @konfig.ts/* packages built on Effect, plus a konfig CLI that loads your .ts sources, renders them, and writes the manifests and Argo CD Application resources into an output directory.

The point is not YAML generation by itself. konfig.ts wires two layers of an application from one TypeScript source:

  • The manifest layer: Deployments, Services, Secrets, Helm releases, Argo CD Applications, and the dependency graph between them.
  • The runtime config layer: the environment variables your process reads at startup, decoded with Effect Config.

Because both layers come from the same declarations, mistakes that would otherwise show up during argocd sync become TypeScript errors or fail-closed render errors instead. Examples: a workload referencing a Secret nobody created, an env var read in code but missing from the pod spec, or a chart pinned by version but not by digest.

What you get

The dependency graph is checked at the type level. Each module declares what it needs (a Secret, a Namespace, a database) and what it provides. When you compose modules into an environment, fromModules refuses to compile until every need has a provider. See Dependency graph.

Environment variables have one contract for both sides. You declare each variable once, as a secret, a literal, or a downward-API value. Binding that contract produces the Deployment env block and the Secret resources; the same contract decodes the variables inside the running process. Rename a variable once and both sides move.

Rendered YAML is deterministic. Output uses stable key ordering (apiVersion, kind, metadata, spec, status first, then alphabetical) and is emitted as YAML 1.1, so kubectl and go-yaml readers do not coerce strings like yes or on. konfig diff compares rendered output against a baseline structurally, so reordered keys and multi-document files do not show up as noise.

Secret backends are typed values. sops, sealed-secrets, and external-secrets each turn a declared secret into the matching custom resource, with schema validation on the binary’s output. Whether a backend requires a source file is encoded in its type, so forgetting the source for a sops backend is a compile error.

Helm releases are digest-verified. Every release must name a chart digest. The cached chart tarball is hashed on every pull and every cache hit, so a chart whose bytes change fails the next render with HelmDigestMismatch.

A compile error instead of a sync failure

The example below is one of the compile-time-catch files shipped in examples/full-stack/infra/envs/. The api module asks for a Secret named ghcr-pull, but no module in the list provides it. fromModules rejects the composition at compile time, before anything is rendered.

examples/full-stack/infra/envs/broken.ts 1 error
const api = defineApi({
  name: "api",
  source: src("api"),
  replicas: 1,
  sopsBase: "infra/secrets"
})
const worker = defineWorker({
  name: "worker",
  source: src("worker"),
  replicas: 1,
  sopsBase: "infra/secrets"
})

export default AppOfApps.fromModules({error TS2345: Missing provider for Image "api", Image "worker" and Secret "ghcr-pull".
Add a module that provides them to AppOfApps.fromModules({ modules }), or check that providers come before consumers in the list.
  target: { repoURL: cluster.repositoryUrl, branch, rootPath },
  defaults: {},
  modules: [api, worker]
})
$ bun run check
infra/envs/broken.ts(30,3): error TS2345: Property '_konfig_unsatisfied' is missing … "Missing provider for Image \"api\"…" | "Missing provider for Image \"worker\"…" | "Missing provider for Secret \"ghcr-pull\"…"

What konfig.ts is not

It does not replace kustomize. If you have hand-written YAML and want to overlay it, konfig.ts is the wrong tool. It owns the manifest source.

It does not mutate anything at runtime. It emits manifests; Argo CD or kubectl applies them. There is no admission controller and no operator.

It is not a platform abstraction. No Crossplane, no OAM, no “Service” model that hides Deployment, Service, and Ingress. Workload.web is a helper that emits those resources explicitly.

It does not replace Helm. It shells out to helm template. Charts you depend on stay charts; each templated document is lifted into the render as a raw YAML manifest.

Requirements

The konfig CLI imports your .ts sources at runtime, so it needs a TypeScript-capable runtime:

RuntimeStatus
BunRecommended, runs .ts with no flags
Node >= 22.18 or >= 23.6Works, native type stripping (packages declare engines.node >= 22)
Node 22.6 to 22.17Works with --experimental-strip-types
tsxWorks: tsx node_modules/.bin/konfig ...

Rendering Helm-based modules calls the helm binary; konfig validate --strict calls kubeconform. Type-checking and in-memory renders of manifest-only projects need neither.

Next

Continue with Installation, then build one Application end to end in Your first environment. To understand what the compile error above catches, read Dependency graph.