- OpenTofu Internals
- JSON Output Format
JSON Output Format
When OpenTofu plans to make changes, it prints a human-readable summary to the terminal. It can also, when run with -out=<PATH>
, write a much more detailed binary plan file, which can later be used to apply those changes.
Since the format of plan files isn't suited for use with external tools (and likely never will be), OpenTofu can output a machine-readable JSON representation of a plan file's changes. It can also convert state files to the same format, to simplify data loading and provide better long-term compatibility.
Use tofu show -json <FILE>
to generate a JSON representation of a plan or state file. See the tofu show
documentation for more details.
The output includes a format_version
key, which has
value "1.0"
. The semantics of this version are:
- We will increment the minor version, e.g.
"1.1"
, for backward-compatible changes or additions. Ignore any object properties with unrecognized names to remain forward-compatible with future minor versions. - We will increment the major version, e.g.
"2.0"
, for changes that are not backward-compatible. Reject any input which reports an unsupported major version.
We will introduce new major versions only within the bounds of the OpenTofu 1.0 Compatibility Promises.
Format Summary
The following sections describe the JSON output format by example, using a pseudo-JSON notation.
Important elements are described with comments, which are prefixed with //
.
To avoid excessive repetition, we've split the complete format into several discrete sub-objects, described under separate headers. References wrapped in angle brackets (like <values-representation>
) are placeholders which, in the real output, would be replaced by an instance of the specified sub-object.
The JSON output format consists of the following objects and sub-objects:
- State Representation — The complete top-level object returned by
tofu show -json <STATE FILE>
. - Plan Representation — The complete top-level object returned by
tofu show -json <PLAN FILE>
. - Values Representation — A sub-object of both plan and state output that describes current state or planned state.
- Configuration Representation — A sub-object of plan output that describes a parsed OpenTofu configuration.
- Expression Representation — A sub-object of a configuration representation that describes an unevaluated expression.
- Block Expressions Representation — A sub-object of a configuration representation that describes the expressions nested inside a block.
- Change Representation — A sub-object of plan output that describes changes to an object.
- Checks Representation — A property of both the plan and state representations that describes the current status of any checks (e.g. preconditions and postconditions) in the configuration.
State Representation
State does not have any significant metadata not included in the common values representation, so the <state-representation>
uses the following format:
Plan Representation
A plan consists of a prior state, the configuration that is being applied to that state, and the set of changes OpenTofu plans to make to achieve that.
For ease of consumption by callers, the plan representation includes a partial representation of the values in the final state (using a value representation), allowing callers to easily analyze the planned outcome using similar code as for analyzing the prior state.
This overall plan structure, fully expanded, is what will be printed by the tofu show -json <planfile>
command.
Values Representation
A values representation is used in both state and plan output to describe current state (which is always complete) and planned state (which omits values not known until apply).
The following example illustrates the structure of a <values-representation>
:
The translation of attribute and output values is the same intuitive mapping from HCL types to JSON types used by OpenTofu's jsonencode
function. This mapping does lose some information: lists, sets, and tuples all lower to JSON arrays while maps and objects both lower to JSON objects. Unknown values and null values are both treated as absent or null.
Output values include a "type"
field, which is a serialization of the value's type. For primitive types this is a string value, such as "number"
or "bool"
. Complex types are represented as a nested JSON array, such as ["map","string"]
or ["object",{"a":"number"}]
. This can be used to reconstruct the output value with the correct type.
Only the "current" object for each resource instance is described. "Deposed" objects are not reflected in this structure at all; in plan representations, you can refer to the change representations for further details.
The intent of this structure is to give a caller access to a similar level of detail as is available to expressions within the configuration itself. This common representation is not suitable for all use-cases because it loses information compared to the data structures it is built from. For more complex needs, use the more elaborate changes and configuration representations.
Configuration Representation
Configuration is the most complicated structure in OpenTofu, since it includes unevaluated expression nodes and other complexities.
Because the configuration models are produced at a stage prior to expression evaluation, it is not possible to produce a values representation for configuration. Instead, we describe the physical structure of the configuration, giving access to constant values where possible and allowing callers to analyze any references to other objects that are present:
Expression Representation
Each unevaluated expression in the configuration is represented with an <expression-representation>
object with the following structure:
Expressions in dynamic
blocks are not included in the configuration representation.
Block Expressions Representation
In some cases, it is the entire content of a block (possibly after certain special arguments have already been handled and removed) that must be represented. For that, we have an <block-expressions-representation>
structure:
For now we expect callers to just hard-code assumptions about the schemas of particular resource types in order to process these expression representations. In a later release we will add new inspection commands to return machine-readable descriptions of the schemas themselves, allowing for more generic handling in programs such as visualization tools.
Change Representation
A <change-representation>
describes the change to the indicated object.
Checks Representation
The JSON representation of checks is experimental and some details may change in future OpenTofu versions based on feedback, even in minor releases of OpenTofu CLI.
A <checks-representation>
describes the current state of a checkable object in the configuration. For example, a resource with one or more preconditions or postconditions is an example of a checkable object, and its check state represents the results of those conditions.
The "checks" model includes both static checkable objects and instances of those objects to ensure that the set of checkable objects will be consistent even if an error prevents full evaluation of the configuration. Any object in the configuration which has associated checks, such as a resource with preconditions or postconditions, will always be included as a checkable object even if a runtime error prevents OpenTofu from evaluating its "count" or "for_each" argument and therefore determining which instances of that object exist dynamically.
When summarizing checks in a UI, we recommend preferring to list only the individual instances and typically ignoring the top-level objects altogether. However, in any case where an object has zero instances, the UI should show the top-level object instead to serve as a placeholder so that the user can see that OpenTofu recognized the existence of the checks, even if it wasn't able to evaluate them on the most recent run.