back to posts

Introducing confit: One Config File to Rule Them All

Alex Miller·June 8, 2026·changelog, coding

confit is a Rust CLI tool that unifies config management into a single confit.toml — handling value interpolation, inline shell evaluation, secret masking, pluggable provider integrations, and SSH key loading. Here's why we built it.

Introducing confit: One Config File to Rule Them All

The Problem with Config

Every project I've worked on has the same config graveyard. A .env file. A .env.local file. A shell script someone wrote two years ago that exports 12 variables before running the server. A separate script that loads SSH keys. A note in the README that says "make sure you have your 1Password CLI configured" with no further explanation. Maybe a Makefile target that wraps all of it together — except it doesn't, because it was written before the AWS SSM integration got added.

The deeper problem isn't any one piece of this. It's that config is stateless knowledge — it lives in your head, in Slack threads, in onboarding docs nobody updates. Every time someone new joins, they spend a day (or three) getting their environment wired up. Every time a secret rotates, you're hunting down four different places that reference it. Every time you add a new environment, you're copy-pasting and hoping you got them all.

I got tired of this pattern. So I built confit.

What confit Is

confit is a Rust CLI tool for unified config management. The premise is simple: one confit.toml file handles everything — value interpolation, inline shell evaluation, secret fetching from external systems, and SSH key loading. It replaces the collection of dotfiles, env scripts, and glue code with a single source of truth that resolves at runtime.

The design goal was to be composable with your existing toolchain, not replace it. confit doesn't care whether your secrets live in 1Password, AWS SSM, Vault, or Terraform outputs — it has a pluggable provider system that maps URI schemes to whatever CLI you already have. It's glue, but with structure.

The project is open source (MIT), written in Rust, and ships as a single static binary. You can install it with:

curl -fsSL https://raw.githubusercontent.com/krondor-corp/confit/main/install.sh | bash

Full documentation is at confit.krondor.org.

How It Works

Here's a minimal confit.toml to show the core ideas:

[vars]
env = "production"
region = "us-east-1"

[app]
name = "my-service"
log_level = "info"
database_url = "op://Infra/{vars.env}/DATABASE_URL"
api_key = "secret://op://Infra/{vars.env}/API_KEY"

[deploy]
cluster = "arn:aws:ecs:{vars.region}:$(aws sts get-caller-identity --query Account --output text):cluster/{app.name}"

A few things are happening here:

  • Interpolation{vars.env} and {app.name} reference other values in the config by dotted path. They resolve before anything else runs.

  • Shell evaluation$(aws sts get-caller-identity ...) runs inline and substitutes the result. No wrapper script needed.

  • Provider URIsop:// is a provider URI. confit sees that prefix and routes it through the mapped CLI (in this case, the 1Password CLI). The value that comes back is the resolved secret.

Provider mappings live in your confit.toml under [providers]. The op:// scheme would be mapped to op read. Want to pull from AWS SSM instead? Map ssm:// to aws ssm get-parameter --with-decryption --query Parameter.Value --output text --name. The provider is just a CLI invocation — if a tool has a CLI, it can be a confit provider.

Once your config is defined, injecting it into a command is one line:

confit run app -- node server.js

That resolves the entire [app] section, sets each key as an environment variable, and execs node server.js. Clean process replacement, no subshell, no lingering env state. You can also use confit show app --format export to emit export KEY=VALUE lines you can eval directly, or YAML if you need to pipe to something else.

Config discovery works the same way git does: confit walks up the directory tree looking for confit.toml. So you can run it from anywhere inside a project and it just works.

Variable precedence follows a clear hierarchy: [vars] defaults are the baseline, CONFIT_VAR_* environment variables override them (useful in CI), and --set CLI flags override everything. This means the same config file works across local dev, staging, and production without modification — you just change the vars.

Secrets and SSH

There are two features I'm particularly happy with: secret masking and SSH agent management.

Secret Masking

Wrapping any value in secret:// tells confit to mask that value in all terminal output — confit show, confit resolve, and logs. The actual resolved value still passes through cleanly when you use confit run or confit ssh. So you can safely run confit show app in front of someone and not have API keys scroll by on screen.

This sounds simple, but it closes the gap between "I want to inspect my config" and "I definitely don't want that in my terminal history." The secret:// wrapper is the annotation. Everything else stays the same.

SSH Agent Management

The confit ssh command solves a specific workflow that I kept writing custom scripts for: you need SSH keys loaded into an agent to run a command, but you don't want those keys persisting in your system agent after the command finishes.

confit ssh --key deploy.private_key -- rsync -avz ./dist user@prod-server:/var/www/

What happens: confit resolves deploy.private_key from your config (which might itself be fetched from 1Password via a provider), spins up a temporary ssh-agent, loads the key, execs your command with SSH_AUTH_SOCK pointing at that agent, and then cleans up when the command exits. The key is in scope exactly as long as you need it.

This pattern comes up constantly in deployment scripts: SSH into a build server, rsync to a remote host, run an Ansible playbook. Before, every team I'd been on handled this differently — some with persistent system agents, some with ssh-agent bash subshells, some just keeping keys unencrypted on disk. confit ssh is the version of this I actually want to use.

Getting Started

Install confit and scaffold a starter config:

# Install
curl -fsSL https://raw.githubusercontent.com/krondor-corp/confit/main/install.sh | bash

# Scaffold a starter config in the current directory
confit init

# Validate everything resolves correctly
confit validate

From there the typical workflow is: define your sections in confit.toml, use confit resolve <path> to spot-check individual values during setup, and then wire confit run into your existing scripts or Makefile targets to replace the manual export blocks.

The full documentation — including provider configuration, variable reference syntax, and all command flags — is at confit.krondor.org. The source is at github.com/krondor-corp/confit.

One file. No more graveyard.