Declarative vs Imperative IAC
Choosing your Infrastructure-as-Code (IaC) stack isn’t as straightforward as it might seem. One helpful early decision is whether you want to work in an imperative or declarative style. This single distinction can help narrow down your options and guide you toward tools that best fit your team’s skills, your operational model, and your infrastructure goals.
Let’s break down the difference using a sandwich metaphor:

Declarative syntax describes what you want. Imperative syntax describes how to do it.
Imperative IaC: Full Control, Full Complexity
Tools like AWS Cloud Development Kit (CDK) and Terraform CDK are prime examples of imperative IaC. They let you write infrastructure using general-purpose programming languages—TypeScript, Python, Go, C#, Java, etc.—integrating tightly with your application codebase and toolchain.
Why teams choose imperative:
- You gain access to the full power of a programming language: conditionals, loops, regex, functions, modules, external API calls, and more.
- Infrastructure logic can be dynamic and context-aware, drawing from systems like AWS Secrets Manager, Parameter Store, feature flag services, and databases.
- It's ideal for use cases like multi-tenant architectures where you may need to create a distinct set of resources per customer—or skip creating them altogether, depending on conditions.
- You can programmatically construct different stacks for different environments (dev, staging, production), giving you flexibility across your deployment pipeline.
What to watch out for:
- Opacity: When infrastructure decisions are driven by a mix of environment variables, feature flags, and external data sources, it becomes harder to answer the question, “What exactly will this deploy?” You’ll often need to run the plan operation and carefully inspect the output just to understand the result.
- Specialization risk: Locking into a general-purpose language narrows your talent pool. Many experienced DevOps engineers are more fluent in YAML (CloudFormation) or HCL (Terraform) than in Python or TypeScript. You’ll also lose out on large open module ecosystems like Cloud Posse that are designed for declarative tools.
Declarative IaC: Clarity and Convention
Declarative IaC—such as Terraform (HCL) or AWS CloudFormation (YAML/JSON)—emphasizes readability and maintainability. You describe your desired infrastructure state, and the tool figures out how to get there.
Why teams choose declarative:
- Simplicity and readability: The code is easy to understand at a glance, even for newcomers.
- Predictability: What you write is what you get. There’s less magic happening at runtime.
- Ecosystem support: Huge libraries of well-tested modules are available, making it easier to follow best practices without reinventing the wheel.
- Lower barrier to entry: Declarative IaC aligns well with how many DevOps practitioners are trained, and reduces the need for deep programming knowledge.
And yet...
- It’s not as limited as it seems. Features like
for_each
in Terraform or CloudFormation’s custom resources can provide a surprising amount of dynamism. - But yes, there are limits. For highly dynamic or conditional logic, you may find yourself wrestling with the constraints of the declarative model—or reaching for workarounds that defeat its simplicity.
So Which Should You Use?
That depends on your priorities.
- If you need maximum flexibility, integrate deeply with other systems, and have a team comfortable with general-purpose languages, the CDK route might suit you well.
- If you value readability, stability, and community support, and you prefer your infrastructure logic to be as transparent as possible, a declarative tool like Terraform or CloudFormation might be the better path.
In the end, it’s not really about which approach is better—it’s about which one is better for you.