skip to content

Declarative vs Imperative

Declarative code states the end result; imperative scripts state the steps to get there. I need to explain why that single distinction is the reason IaC tools exist at all, because it is a near-guaranteed opening question.

on this pageshow

questions

5

What is the difference between declarative and imperative infrastructure code, and why do mainstream infrastructure-as-code tools choose the declarative model?

level: juniorimportance: must knowfreq 88%

answer

  1. result versus steps
  2. the file is a description, not a transcript
  3. delete the code, the resource goes
  4. the engine derives order and actions
  5. syntax is not the distinction

basics

~20 s

Declarative code describes the end state you want and lets the tool work out the steps to reach it; imperative code lists the steps themselves. IaC tools are declarative so the same file can be applied repeatedly and still describe one known result.

solid answer

~50 s

An imperative script says *do these steps*: create this network, then this instance, then attach this disk. Declarative code says *this is what should exist* and hands the tool the job of working out which calls to make, in what order, and whether anything needs to be done at all. The practical payoff is that the file is a description rather than a transcript: it is readable as the current intended shape of the estate, it can be applied against a fresh account or an existing one and end up in the same place, and removing a declaration is a meaningful instruction rather than a no-op. It also lets the tool derive execution order from the dependencies between the things you declared, instead of relying on you to sequence every call correctly. Imperative scripts, by contrast, only tell you what someone did once, on some day, against some starting state.

go deeper

for a junior

Be ready to give the one-line distinction — result versus steps — and one concrete example of each. Say plainly that the declarative file describes what should exist, so applying it twice does not build things twice.

for a middle

Explain the mechanics behind the slogan: the engine compares your declaration with reality, derives which calls to make and in what order, and treats a removed declaration as an instruction to remove the resource. Point out that file format is not the distinction.

for a senior

Show where the model leaks in production — shell-out escape hatches that the tool cannot preview or reverse, resources created out of band that no declaration covers, and the discipline needed to keep the repository the actual source of truth.

for a principal

Own the organizational consequence: declaring everything is a policy choice with a cost, and the estate splits into what is modelled and what is not. Be able to argue where that line sits, who is allowed to punch through it, and how you keep the unmodelled remainder from growing.

## The distinction in one line **Imperative** code specifies the *steps*. **Declarative** code specifies the *result*, and the tool derives the steps. An imperative provisioning script is a sequence of API calls: create a network, wait for it, create a subnet inside it, create a security group, launch an instance referencing all three. Everything about the ordering, the waiting, the error handling and the "does this already exist?" checking is your responsibility, because the script is just a program that makes calls. A declarative configuration is a *set of statements about what should be true*: a network with this address range exists; a subnet with this range exists inside it; an instance of this size exists on that subnet. There is no `create` verb, because creating is an implementation detail the engine chooses when it compares the declaration with what is actually there. ## What the declaration buys you **The file is a description, not a transcript.** A script tells you what someone did on one particular day against one particular starting state. A declarative file tells you what the estate is *supposed to look like right now*. That is what makes code review meaningful: a reviewer reads the target shape, not a replay of somebody's terminal history. **Applying twice is safe.** Because the statements describe an end state, running the tool again against an estate that already matches produces no changes. A script that calls a create API twice creates two things (or crashes on the second attempt) unless you hand-wrote the guard. **Deletion becomes expressible.** This is the property people forget. If you remove a resource declaration and apply, a declarative tool understands that the resource should no longer exist and removes it, because your file is the *whole* statement of intent, not an increment on top of it. Deleting a line from an imperative script does nothing at all — the resource that the line created is still out there, and now nothing in the repository mentions it. **Ordering is derived, not authored.** Because a declaration references other declarations, the tool can work out which things must exist before which others and sequence the calls itself, in parallel where it can. In an imperative script, the order is whatever you typed, and getting it wrong shows up as an intermittent failure. ## Where imperative thinking still lives The boundary is fuzzier than the slogan suggests, and interviewers like to poke at it. Configuration-management tools that execute a list of tasks top to bottom are best described as *imperative sequencing of declarative steps*: the run order is yours, but each individual step states a desired condition — this package is installed, this service is running — and does nothing when the condition already holds. Tools whose authoring language is a general-purpose programming language are also frequently mislabelled. Loops, conditionals and functions in your source do not make the deployment imperative; what matters is whether the program's *output* is a complete description of desired state that the engine then compares against reality. And almost every declarative tool has an escape hatch that shells out to a script. Using it is sometimes right, but each use punches a hole in the properties above: the tool cannot inspect what the script did, so it cannot tell you in advance what will change, and it cannot undo it when you delete the declaration. ## The trap answers "Declarative means YAML, imperative means Bash" is wrong — the file format is irrelevant. You can write an imperative program in YAML (a list of ordered commands) and a declarative description in Python. Likewise, "declarative means the language has no loops" is wrong: expressiveness in the authoring language and the execution model are independent axes. The useful test to state in an interview is: **if I delete a chunk of this code and re-run the tool, does the corresponding infrastructure go away?** If yes, you are looking at a declarative model, whatever the syntax. If deleting the code is a no-op, it is a script, however nicely it is formatted. ## Why the industry landed here The original way to build infrastructure was a person clicking a console; the first automation was a script that replayed those clicks. Scripts scale badly for the same reason a transcript scales badly — they answer "what happened" rather than "what should be true", and every re-run has to defensively re-derive the starting state. Declarative tooling moved that burden into the engine, which is why nearly every widely used provisioning tool today is declarative at the point of deployment, whatever its authoring surface looks like.

  • Are configuration-management tools that run a list of tasks in order declarative or imperative?
    Both, at different levels. The play or task list executes top to bottom in the order you wrote it, which is imperative sequencing. But each individual task states a desired condition — this package present, this service running — and takes no action when the condition already holds. So you get idempotent steps under an authored ordering, rather than a dependency graph the tool derives for you.
  • If declarative is clearly better, why did infrastructure automation start with scripts?
    Because scripts are the direct automation of what a human was already doing: replaying console clicks as API calls. They need no model, no recorded inventory and no engine. Declarative tooling only becomes worth the machinery once the estate is large enough that "what should be true" is a more useful question than "what did we run last Tuesday", and once you need repeatability across environments.
  • What does treating the declarative code as the source of truth actually commit a team to?
    That changes go through the repository and not the console, because anything done out of band is either silently reverted on the next apply or quietly diverges. It also commits you to keeping the code complete — a resource nobody declared is invisible to the tool, so it will never be updated, reviewed or cleaned up with the rest of the estate.

Imperative is turn-by-turn directions to the driver; declarative is giving the address and letting the driver route around traffic. If the road is closed, only the address still gets you there.

saying these in an interview costs you the question

  • Declarative just means YAML instead of a shell script
  • Declarative means the language has no loops or conditionals
  • Deleting a resource from the code cannot destroy anything
  • Declarative tools run resources in the order you wrote them
  • Anything stored in a git repository counts as infrastructure as code

context

open as a page

Why is idempotency the property that makes declarative infrastructure code usable, and what typically makes a hand-written provisioning shell script non-idempotent?

level: middleimportance: must knowfreq 66%

basics

~20 s

Idempotency means applying the same configuration again leaves the same end state, so a run can be repeated or resumed safely. Scripts break it by using create-and-append operations that stack up on every execution instead of asserting a condition.

open as a page

What is the difference between infrastructure as code and configuration as code, and how does that difference show up in the kinds of tools a team ends up running?

level: middleimportance: should knowfreq 50%

basics

~20 s

Infrastructure as code declares the resources themselves — networks, machines, managed services. Configuration as code declares the state inside or on top of them, such as installed packages, files and services. The two overlap but answer different questions.

open as a page

Your team has adopted a declarative IaC tool. Where does imperative scripting against a cloud SDK or CLI still legitimately win, and how do you keep those scripts from becoming invisible operations?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Scripting still wins for one-shot actions rather than durable resources: operational tasks, bulk data work, bootstrapping the tooling itself, and anything with no resource model. Keep those scripts in the repository, reviewed, re-runnable and logged like any other change.

open as a page

If infrastructure is written in a general-purpose programming language such as Python or TypeScript, does that make the approach imperative rather than declarative?

level: middleimportance: nice to knowfreq 30%

basics

~20 s

No. The authoring language and the deployment model are separate axes. A program with loops and conditionals can still produce a complete description of desired state, which an engine then compares against reality before changing anything.

open as a page