Imperative and declarative Kubernetes configuration
Kubernetes is built around desired state. You describe what resources should exist and controllers continually work to make the live cluster match that desired state.
There are two common ways to change that state:
- Imperative commands tell Kubernetes to perform an operation immediately.
- Declarative configuration describes the desired resource state in files and applies those files to the cluster.
Both are useful. The right choice depends on whether you are experimenting interactively or managing repeatable production configuration.
Imperative Kubernetes commands
An imperative command directly asks the API server to create or modify a resource.
For example:
kubectl run nicepod \
--image=nginx:1.29Verify the result:
kubectl get pod nicepodImperative commands are fast and convenient for development, troubleshooting and one-off administration.
Declarative Kubernetes configuration
The declarative approach stores the desired state in YAML or JSON and uses kubectl apply to reconcile the live object with that configuration.
A Pod manifest might look like this:
apiVersion: v1
kind: Pod
metadata:
name: nicepod
labels:
app: demo
spec:
containers:
- name: web
image: nginx:1.29
ports:
- containerPort: 80Apply it:
kubectl apply -f nicepod.yamlIf the object does not already exist, apply creates it. If the managed configuration changes later, another apply updates the live object.
Preview declarative changes with kubectl diff
A useful modern workflow is to preview the effect of a manifest before applying it:
kubectl diff -f nicepod.yamlThen apply the change:
kubectl apply -f nicepod.yamlThis makes declarative changes easier to review in scripts, CI/CD pipelines and production operations.
Imperative Deployment example
Create a Deployment from the command line:
kubectl create deployment cooldeploy \
--image=nginx:1.29Scale it to three replicas:
kubectl scale deployment/cooldeploy \
--replicas=3Check the Deployment:
kubectl get deployment cooldeployDeclarative Deployment example
apiVersion: apps/v1
kind: Deployment
metadata:
name: cooldeploy
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29
ports:
- containerPort: 80Apply it:
kubectl apply -f deployment.yamlThe manifest now captures the Deployment's intended image, labels and replica count in a form that can be reviewed, versioned and reused.
Namespace examples
Create a Namespace imperatively:
kubectl create namespace coolspaceThe declarative equivalent is:
apiVersion: v1
kind: Namespace
metadata:
name: coolspace
labels:
environment: devApply it with:
kubectl apply -f coolspace.yamlImperative Service example
Expose the Deployment with a Service:
kubectl expose deployment cooldeploy \
--name=my-service \
--port=8080 \
--target-port=80 \
--type=LoadBalancerThen inspect it:
kubectl get service my-serviceA LoadBalancer Service requests an external load balancer from a compatible cloud or local implementation. It does not guarantee that every Kubernetes environment will immediately provide a publicly routable IP address.
Declarative Service example
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 8080
targetPort: 80
type: LoadBalancerApply the Service:
kubectl apply -f myservice.yamlThe original article contained a filename typo, myservice-yaml. The correct example uses myservice.yaml.
Imperative does not mean unaudited
Imperative configuration is not inherently unaudited. Kubernetes API requests can be captured by Kubernetes audit logging when the cluster is configured for it.
The real advantage of declarative configuration is that the desired state itself can live in source control. That provides reviewable diffs, change history, pull requests, rollback points and a natural foundation for GitOps workflows.
Why declarative configuration is preferred for production
For production systems, declarative manifests are usually easier to operate because they make the intended cluster state reproducible.
Benefits include:
- configuration can be stored in Git;
- changes can be code-reviewed;
- the same resources can be recreated in another cluster;
kubectl diffcan preview changes;- CI/CD and GitOps tools can automate reconciliation; and
- configuration drift becomes easier to detect and correct.
When imperative commands are better
Imperative commands remain valuable for:
- learning Kubernetes;
- temporary test resources;
- interactive troubleshooting;
- quick scaling operations;
- administrative inspection; and
- generating a starting point for manifests.
Generate YAML without creating the resource
A useful compromise is to use an imperative generator to produce declarative YAML:
kubectl create deployment cooldeploy \
--image=nginx:1.29 \
--dry-run=client \
-o yamlRedirect the output to a file:
kubectl create deployment cooldeploy \
--image=nginx:1.29 \
--dry-run=client \
-o yaml \
> deployment.yamlYou can then edit, review and apply that manifest declaratively.
Do not casually mix management styles
If a resource is managed declaratively with kubectl apply, treat its configuration files as the source of truth.
Ad hoc imperative edits can create configuration drift when those changes are not reflected back into the manifests. The next declarative reconciliation may overwrite them.
For production resources, pick a management model and use it consistently.
Imperative vs. declarative Kubernetes cheat sheet
| Task | Imperative | Declarative |
|---|---|---|
| Create Pod | kubectl run ... |
kubectl apply -f pod.yaml |
| Create Deployment | kubectl create deployment ... |
kubectl apply -f deployment.yaml |
| Create Namespace | kubectl create namespace ... |
kubectl apply -f namespace.yaml |
| Create Service | kubectl expose ... |
kubectl apply -f service.yaml |
| Preview changes | Command-specific | kubectl diff -f ... |
| Best fit | Interactive work | Repeatable operations |
The simplest distinction is this: imperative commands describe an action to perform now, while declarative configuration describes the state Kubernetes should maintain. Use imperative commands for speed and exploration, and declarative manifests for repeatable, reviewable production configuration.