Terraform, getting output from null_resource, local-exec and the AWS CLI
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Terraform users often try to capture command output from null_resource with local-exec, then discover that provisioners are poor data interfaces. local-exec is designed for side effects, not for feeding structured values into Terraform graph evaluation. For stable infrastructure code, provider-native data sources or external data sources are usually the correct path.
Core Sections
What null_resource and local-exec are good for
null_resource can run actions with provisioners, and local-exec runs shell commands on the machine executing Terraform. This is useful for notifications, bootstrap hooks, or local scripts that do not need to become Terraform state.
The command runs, but stdout is not exposed as typed Terraform attributes.
In newer Terraform versions, terraform_data is often a better fit than null_resource when you need a placeholder object for lifecycle wiring. Even then, the same rule applies: provisioners are for side effects, not for returning typed data back into the expression graph.
Why parsing local-exec output is brittle
Terraform plans resources declaratively. Provisioners run after resource creation and do not integrate cleanly with expression graph dependencies. Trying to parse command output for later resources creates hidden ordering and weak type guarantees.
Common issues:
- command output format changes,
- environment differences between local and CI,
- partial failures leaving unclear state.
Prefer provider-native AWS data sources first
If AWS provider already exposes what you need, use it directly.
This keeps configuration typed, testable, and predictable.
Use external data source for custom command results
When provider data source is unavailable, use external with strict JSON output.
Example script:
Return only JSON object with string values unless your parser intentionally handles nested structures.
The important improvement over local-exec is timing. external runs as a data source, so Terraform can reason about its result during graph evaluation instead of treating command output as an after-the-fact side effect.
Keep ordering explicit with dependencies
If custom command depends on created resources, express dependency clearly instead of relying on side effects.
Explicit dependencies make plan behavior understandable for teammates and CI pipelines.
Handle authentication context consistently
AWS CLI output depends on credentials, profile, and region. A command that works locally may fail in CI due to missing role assumption or profile configuration.
Define one authentication strategy across environments and document it. For automation, prefer role-based ephemeral credentials over static keys.
Error handling and retry strategy
External scripts should fail fast with useful stderr when commands fail. For transient APIs, retries can be added carefully in script, but avoid masking persistent misconfiguration.
Never emit fake fallback JSON on failure unless you also signal failure clearly. Silent fallback creates dangerous misconfigurations.
Security considerations
Avoid exposing sensitive command outputs in Terraform outputs or logs. If values are sensitive, mark outputs as sensitive and limit log verbosity in CI.
Practical migration guideline
If current code relies heavily on null_resource output hacks, migrate incrementally:
- replace easy cases with provider data sources,
- move custom command output to
external, - remove redundant null resources,
- add CI checks for deterministic output.
This gives cleaner state and fewer surprise ordering bugs.
Common Pitfalls
- Treating
local-execstdout as reliable Terraform data channel. - Using
null_resourceto model data dependencies instead of resources and data sources. - Returning non-JSON or inconsistent JSON from
externalscripts. - Ignoring AWS credential context differences between local and CI runs.
- Logging sensitive command output in plain Terraform outputs.
Summary
- Use
local-execfor side effects, not structured Terraform values. - Prefer provider-native AWS data sources whenever possible.
- Use
externaldata source with strict JSON for custom data retrieval. - Keep dependencies and authentication explicit for reproducible behavior.
- Reduce
null_resourceusage over time to improve maintainability and plan clarity.
Related reading
- Terraform How to migrate state between projects?
- Terraform kubernetes_config_map --from-env-file
- Terraform lookup AWS region
- terraform output Google Kubernetes cluster inggress load balancer ip
- Terraform, ignore_changes and sub-blocks
- Terraform kubectl provider error failed to create kubernetes rest client for read of resource
- terraform reference existing s3 bucket and dynamo table
- Text files uploaded to S3 are encoded strangely?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.