I think the best way to think about these is that computed
is mostly independent of optional
vs. required
.
The flag computed
means that the provider may choose an arbitrary value (as long as it has the correct type) for that attribute. If computed
is not set, then only the configuration can choose a value and the provider will honor it.
The presence of either optional
or required
signals that the configuration can provide a value for the attribute. In the case of required
, the configuration must provide a value for the attribute. In the case of optional
, if the attribute is not set in configuration then its value is null
. optional
and required
are mutually-exclusive because their definitions conflict with one another.
The trickiest case is the one where both optional
and computed
appear together. That combines together the two situations above, meaning that the attribute can be chosen either by the configuration or by the provider, with the configuration taking precedence. Or to phrase it in a more user-oriented way: the provider can choose a default value to use if and only if there is no value set in the configuration.
In the interests of completeness, I’ll note also that required
and computed
conflict with one another because (given that configuration always takes priority over a provider’s defaults) there is no situation where a default value can ever be selected for a required
attribute.
Perhaps the above will be easier to follow as a table of the valid combinations:
computed |
optional |
required |
Meaning |
✓ |
|
|
The value is always chosen by the provider. |
|
✓ |
|
The value is chosen by the configuration, or null if no value is set there. |
|
|
✓ |
The value is chosen by the configuration and must always be set there. |
✓ |
✓ |
|
The value is chosen by the configuration if set, or by the provider if not set. |
Looking at the JSON format documentation I can see that the comment attached to computed
is not complete, because it only discusses the case where computed
is used alone and doesn’t mention how it interacts with optional
.
Another thing I want to note here, since I can see the potential for confusion, is that the terraform providers schema -json
output is describing the schema in the terms Terraform Core understands, while the Terraform SDK (what the “extend” section of the documentation is discussing) is at a higher level of abstraction due to its own built-in validation behaviors and so while the concepts do overlap slightly, the extend documentation includes some details that do not apply to the terraform providers schema -json
output.
Finally, some older provider features currently get a pass for exactly honoring the above requirements as an allowance for historical compatibility. That should phase out in the coming months as support for Terraform 0.11 in new provider releases comes to an end and the SDK can therefore use more modern behaviors throughout, but as I write this there are some situations you may encounter where a provider behaves as if it had set computed
to true
even though it actually did not.
For use-cases involving configuration generation those compatibility exceptions are usually not a problem since the values chosen by the provider are not involved in code-generation use-cases anyway. I point it out just in case you have different goals in your work where it might be significant that the final result of a Terraform action can potentially differ from the configuration even though computed
wasn’t set.