Build infrastructure the way nature builds matter
EIF is a provider-agnostic Terraform framework that models infrastructure with the elegance of chemistry. Compose atoms into molecules, molecules into matter — on any cloud. The CLI lives here; the component library lives in eif-library ↗.
eif package install && eif apply aws three-tier-app devFounding principles
Modern cloud infrastructure suffers from two opposite extremes: the monolith temptation — a single Terraform repository that holds everything — and the chaotic fragmentation of disconnected modules. EIF proposes a third way, inspired by chemistry: every cloud resource has its own atomic identity, composable with precision into increasingly complex structures, up to fully deployable applications.
"Build infrastructure the way nature builds matter — atom by atom,
molecule by molecule, until complexity emerges from simplicity."
The compositional model
Each level builds on the previous. Atoms and molecules are internal building blocks — they are never deployed directly. Matter is the only user-facing level, the sole entry point for every deployment.
LEVEL 01 — ATOM
A single cloud service in plain HCL. The primitive building block of the framework — scoped to one service only. Namespaced by cloud. Atoms are composed by molecules and are never deployed directly.
LEVEL 02 — MOLECULE
A reusable architectural blueprint that combines atoms into a coherent pattern. Molecules are composed by matter and are never deployed directly.
LEVEL 03 — MATTER
A complete application composed of molecules. Structure declared once in composition.json with exact semver pins — the composition is the lock. Each <env>.json is a flat variable pool; environment is injected automatically.
Cloud agnostic
Each cloud provider is a self-contained directory. Adding support for a new cloud
requires no changes to eif.py — just drop a template in the right place.
providers/ ├── aws/ │ └── provider.tf.j2 # terraform{} + provider "aws" — profile or assume_role ├── azure/ │ └── provider.tf.j2 # terraform{} + provider "azurerm" — subscription + tenant └── gcp/ └── provider.tf.j2 # terraform{} + provider "google" — project + region
The accounts.json entry declares "provider": "aws" (or azure, gcp).
eif render resolves the right template, renders it with account config as context,
and prepends it automatically to every rendered output — matter templates contain only module blocks.
To contribute a new provider: create providers/<cloud>/provider.tf.j2,
add atoms under atoms/<cloud>/ and molecules under molecules/<cloud>/.
Stability guarantee
Atoms and molecules use semantic versioning (MAJOR.MINOR.PATCH).
Every breaking change creates a new version directory — compositions pinned to old versions are never touched.
patch → bug fix, no interface change 1.0.0 → 1.0.1
minor → new optional variable or output 1.0.0 → 1.1.0
major → breaking change (required var, type change, removed output) 1.0.0 → 2.0.0
atoms/aws/storage/rds/1.0.0/ ← matter stays pinned here
atoms/aws/storage/rds/2.0.0/ ← breaking: new required variable
# composition.json — the composition is the lock { "matter": "three-tier-app", "molecules": [ { "name": "db", "source": "aws/db", "version": "1.2.0" }, { "name": "spa", "source": "aws/spa", "version": "3.0.0" } ] } # diff what would break before updating eif diff molecule aws db 1.2.0 2.0.0 # update with interactive diff + confirmation eif package update aws/db eif package update --safe # skip major bumps
Package management
eif package is EIF's package manager for infrastructure components.
Packages are pre-built molecules from the registry. Atoms are never installed directly — they are bundled automatically
as dependencies when their parent molecule is downloaded.
Install is explicit: nothing downloads automatically.
MANIFEST
Project manifest. Declares named registries with type, URL, and priority. Auth lives in eif.secure.json (gitignored).
CACHE
Local store of downloaded molecules and their bundled atom dependencies. Gitignored. Shared across all matters in the project.
If a molecule is missing when rendering, eif fails fast with a clear install message.
Atom dependencies are bundled automatically when a molecule is installed — their relative paths
are preserved in eif_packages/ so Terraform resolves them without modification.
Local molecules (authored but not yet published) coexist alongside registry packages —
the renderer checks eif_packages/ first, then falls back to local molecules/.
Developer experience
eif init [folder] scaffolds a new project in seconds — pass a folder name and it is created automatically. eif new adds atoms, molecules, and matters.
eif remove deletes them with a confirmation prompt. All commands are fully interactive.
# initialise in a new folder (created automatically) eif init my-infra # or initialise in the current directory eif init ◻ aws ◻ azure ◻ gcp (space to select) ✨ created → providers/aws/ providers/azure/ ✨ created → accounts.json · eif.project.json · .gitignore · matters/ # scaffold a new atom — prompts: name, provider, category, bump type eif new atom 📦 atoms/aws/networking/cdn-origin — no existing versions, creating 1.0.0 ✨ created → atoms/aws/networking/cdn-origin/1.0.0/{main,variables,outputs}.tf # scaffold a new matter — queries registry live, pins latest versions eif new matter serverless-api ✨ created → matters/serverless-api/aws/{composition.json,dev.example.json,main.tf.j2} # remove a component — shows files, confirms before deleting eif remove molecule aws db remove molecules/aws/db/ - molecules/aws/db/1.0.0/main.tf delete molecules/aws/db? (y/N)
If an atom or molecule already exists, the command reports the latest version
and asks for the bump type — patch / minor / major — computing the next semver automatically.
Providers are auto-detected from the providers/ directory —
no hardcoded list, no config needed.
Deployment lifecycle
EIF wraps the full Terraform lifecycle. Every successful apply saves a snapshot
of the rendered main.tf — locally and, if a backend is configured, in the same
remote bucket as the Terraform state. Rollback restores any previous snapshot and re-applies.
# plan — render + terraform plan (no changes applied) eif plan aws three-tier-app dev # apply — render + init + apply + snapshot on success eif apply aws three-tier-app dev [eif] rendered → matters/three-tier-app/aws/.rendered/dev/main.tf [eif] running terraform -chdir=... init [eif] running terraform -chdir=... apply [eif] snapshot → .history/dev/20260320T143012Z/main.tf # rollback — pick a snapshot and re-apply eif rollback aws three-tier-app dev snapshot to restore: ❯ 20260320T143012Z 20260319T091500Z 20260318T182244Z # destroy — terraform destroy against last rendered output eif destroy aws three-tier-app dev
Add a backend key to any account in accounts.json to enable remote state.
EIF injects the correct backend {} block automatically — S3, Azure Blob, or GCS.
Bootstrap the state bucket in one command:
eif config backend aws three-tier-app prod
eif add account
← add an account entry (one-time, per account)
Repository layout
This repo is the CLI tool only. The component library — atoms, molecules, and matters — lives in eif-library ↗. Each directory is self-contained and follows a consistent naming convention.
eif/ # this repo — CLI tool only │ ├── eif.py # renderer, lifecycle, scaffold, package CLI ├── pyproject.toml # Python project (uv / hatchling) │ └── examples/ # Reference implementation ├── accounts.example.json ├── eif.project.json # project manifest ├── providers/ # aws · azure · gcp ├── atoms/ ├── molecules/ └── matters/
Your project repo follows the full component structure:
your-project/ # your infrastructure repo │ ├── accounts.json # env → cloud account config ├── eif.project.json # project manifest (name + registries) ├── eif_packages/ # gitignored — downloaded atoms + molecules │ ├── atoms/<cloud>/<cat>/<name>/1.0.0/ │ └── molecules/<cloud>/<name>/1.2.0/ │ ├── providers/ # Pluggable cloud provider templates │ ├── aws/provider.tf.j2 · backend.tf.j2 │ └── ... │ ├── atoms/ # local atoms (authoring only) ├── molecules/ # local molecules (authoring only) │ └── matters/ # Deployable applications └── <name>/<cloud>/ ├── composition.json # molecule list + exact semver pins ├── <env>.json # flat variable pool per environment └── main.tf.j2 # wiring template
Star the repos, open an issue, or contribute atoms and molecules to eif-library.