Large Value Handling

Multi-line and long values are formatted clearly with line-by-line diffs in collapsible sections.

all providers

Configuration files, JSON policies, and user data scripts can be huge. tfplan2md automatically detects large values and moves them to a dedicated section with collapsible details, keeping the main report clean.

❌ Without tfplan2md

Raw Terraform Output
# azurerm_api_management_policy.global will be updated in-place
~ resource "azurerm_api_management_policy" "global" {
    ~ xml_content = "<policies>\n  <inbound>\n    <!-- Rate limiting policy -->\n    <rate-limit calls=\"100\" renewal-period=\"60\" />\n    <!-- IP filtering -->\n    <ip-filter action=\"allow\">\n      <address>10.0.0.0/24</address>\n      <address>172.16.0.0/16</address>\n    </ip-filter>\n    <!-- CORS policy -->\n    <cors allow-credentials=\"true\">\n      <allowed-origins>\n        <origin>https://example.com</origin>\n        <origin>https://app.example.com</origin>\n      </allowed-origins>\n      <allowed-methods>\n        <method>GET</method>\n        <method>POST</method>\n        <method>PUT</method>\n        <method>DELETE</method>\n      </allowed-methods>\n      <allowed-headers>\n        <header>Content-Type</header>\n        <header>Authorization</header>\n        <header>X-Requested-With</header>\n      </allowed-headers>\n    </cors>\n    <!-- Authentication with Azure AD -->\n    <validate-jwt header-name=\"Authorization\" failed-validation-httpcode=\"401\" failed-validation-error-message=\"Unauthorized\">\n      <openid-config url=\"https://login.microsoftonline.com/common/.well-known/openid-configuration\" />\n      <audiences>\n        <audience>api://12345678-1234-1234-1234-123456789abc</audience>\n      </audiences>\n      <required-claims>\n        <claim name=\"roles\" match=\"any\">\n          <value>Reader</value>\n          <value>Writer</value>\n        </claim>\n      </required-claims>\n    </validate-jwt>\n    <!-- Set backend service URL -->\n    <set-backend-service base-url=\"https://backend-old.example.com\" />\n    <!-- Add custom headers -->\n    <set-header name=\"X-Environment\" exists-action=\"override\">\n      <value>Production</value>\n    </set-header>\n    <set-header name=\"X-Request-Id\" exists-action=\"override\">\n      <value>@(Guid.NewGuid().ToString())</value>\n    </set-header>\n  </inbound>\n  <backend>\n    <base />\n  </backend>\n  <outbound>\n    <base />\n    <!-- Response caching -->\n    <cache-store duration=\"3600\" />\n    <!-- Remove internal headers -->\n    <set-header name=\"X-AspNet-Version\" exists-action=\"delete\" />\n    <set-header name=\"X-Powered-By\" exists-action=\"delete\" />\n  </outbound>\n  <on-error>\n    <base />\n    <!-- Log errors to Application Insights -->\n    <trace source=\"policy-error\" severity=\"error\">\n      <message>@(context.LastError.Message)</message>\n      <metadata name=\"request-id\" value=\"@(context.RequestId)\" />\n    </trace>\n  </on-error>\n</policies>" ->
"<policies>\n  <inbound>\n    <!-- Rate limiting policy with increased limits -->\n    <rate-limit calls=\"200\" renewal-period=\"60\" />\n    <!-- IP filtering with additional networks -->\n    <ip-filter action=\"allow\">\n      <address>10.0.0.0/24</address>\n      <address>172.16.0.0/16</address>\n      <address>192.168.1.0/24</address>\n    </ip-filter>\n    <!-- CORS policy with additional origins -->\n    <cors allow-credentials=\"true\">\n      <allowed-origins>\n        <origin>https://example.com</origin>\n        <origin>https://app.example.com</origin>\n        <origin>https://portal.example.com</origin>\n      </allowed-origins>\n      <allowed-methods>\n        <method>GET</method>\n        <method>POST</method>\n        <method>PUT</method>\n        <method>DELETE</method>\n        <method>PATCH</method>\n      </allowed-methods>\n      <allowed-headers>\n        <header>Content-Type</header>\n        <header>Authorization</header>\n        <header>X-Requested-With</header>\n        <header>X-API-Key</header>\n      </allowed-headers>\n    </cors>\n    <!-- Authentication with Azure AD -->\n    <validate-jwt header-name=\"Authorization\" failed-validation-httpcode=\"401\" failed-validation-error-message=\"Unauthorized\">\n      <openid-config url=\"https://login.microsoftonline.com/common/.well-known/openid-configuration\" />\n      <audiences>\n        <audience>api://12345678-1234-1234-1234-123456789abc</audience>\n      </audiences>\n      <required-claims>\n        <claim name=\"roles\" match=\"any\">\n          <value>Reader</value>\n          <value>Writer</value>\n          <value>Admin</value>\n        </claim>\n      </required-claims>\n    </validate-jwt>\n    <!-- Set backend service URL to new endpoint -->\n    <set-backend-service base-url=\"https://backend-new.example.com\" />\n    <!-- Add custom headers -->\n    <set-header name=\"X-Environment\" exists-action=\"override\">\n      <value>Production</value>\n    </set-header>\n    <set-header name=\"X-Request-Id\" exists-action=\"override\">\n      <value>@(Guid.NewGuid().ToString())</value>\n    </set-header>\n    <set-header name=\"X-API-Version\" exists-action=\"override\">\n      <value>2.0</value>\n    </set-header>\n    <!-- Request throttling per user -->\n    <quota-by-key calls=\"10000\" renewal-period=\"3600\" counter-key=\"@(context.Request.Headers.GetValueOrDefault(&quot;Authorization&quot;,&quot;&quot;))\" />\n  </inbound>\n  <backend>\n    <base />\n    <!-- Retry policy for backend failures -->\n    <retry condition=\"@(context.Response.StatusCode &gt;= 500)\" count=\"3\" interval=\"2\" first-fast-retry=\"true\" />\n  </backend>\n  <outbound>\n    <base />\n    <!-- Response caching with vary-by headers -->\n    <cache-store duration=\"3600\" vary-by-developer=\"false\" vary-by-developer-groups=\"false\">\n      <vary-by-header>Accept</vary-by-header>\n      <vary-by-header>Accept-Encoding</vary-by-header>\n    </cache-store>\n    <!-- Remove internal headers -->\n    <set-header name=\"X-AspNet-Version\" exists-action=\"delete\" />\n    <set-header name=\"X-Powered-By\" exists-action=\"delete\" />\n    <!-- Add security headers -->\n    <set-header name=\"X-Content-Type-Options\" exists-action=\"override\">\n      <value>nosniff</value>\n    </set-header>\n    <set-header name=\"X-Frame-Options\" exists-action=\"override\">\n      <value>DENY</value>\n    </set-header>\n  </outbound>\n  <on-error>\n    <base />\n    <!-- Log errors to Application Insights with additional context -->\n    <trace source=\"policy-error\" severity=\"error\">\n      <message>@(context.LastError.Message)</message>\n      <metadata name=\"request-id\" value=\"@(context.RequestId)\" />\n      <metadata name=\"operation-name\" value=\"@(context.Operation.Name)\" />\n      <metadata name=\"status-code\" value=\"@(context.Response.StatusCode.ToString())\" />\n    </trace>\n    <!-- Send error notification -->\n    <send-one-way-request mode=\"new\">\n      <set-url>https://monitoring.example.com/api/alerts</set-url>\n      <set-method>POST</set-method>\n      <set-header name=\"Content-Type\" exists-action=\"override\">\n        <value>application/json</value>\n      </set-header>\n      <set-body>@{\n        return new JObject(\n          new JProperty(&quot;error&quot;, context.LastError.Message),\n          new JProperty(&quot;requestId&quot;, context.RequestId),\n          new JProperty(&quot;timestamp&quot;, DateTime.UtcNow.ToString())\n        ).ToString();\n      }</set-body>\n    </send-one-way-request>\n  </on-error>\n</policies>"
      # (1 unchanged attribute hidden)
  }

112-line XML policy embedded in strings with \n escape sequences—nearly impossible to spot changes.

✅ With tfplan2md

Large Value Diff Output

🔄 azurerm_api_management_policy.global

Attribute Before After
xml_content (see below) (see below)

Large values: xml_content (112 lines, 57 changed)

xml_content:
<policies>
  <inbound>
-     <!-- Rate limiting policy -->
-     <rate-limit calls="100" renewal-period="60" />
+     <!-- Rate limiting policy with increased limits -->
+     <rate-limit calls="200" renewal-period="60" />
+     <!-- IP filtering with additional networks -->
    <ip-filter action="allow">
      <address>10.0.0.0/24</address>
      <address>172.16.0.0/16</address>
+       <address>192.168.1.0/24</address>
    </ip-filter>
-     <!-- CORS policy -->
+     <!-- CORS policy with additional origins -->
    <cors allow-credentials="true">
      <allowed-origins>
        <origin>https://example.com</origin>
        <origin>https://app.example.com</origin>
+         <origin>https://portal.example.com</origin>
      </allowed-origins>
      <allowed-methods>
        <method>GET</method>
        <method>POST</method>
        <method>PUT</method>
        <method>DELETE</method>
+         <method>PATCH</method>
      </allowed-methods>
      <allowed-headers>
        <header>Content-Type</header>
        <header>Authorization</header>
        <header>X-Requested-With</header>
+         <header>X-API-Key</header>
      </allowed-headers>
    </cors>
    <!-- Authentication, backend, headers... -->
-     <set-backend-service base-url="https://backend-old.example.com" />
+     <set-backend-service base-url="https://backend-new.example.com" />
    ... 80+ more lines with inline character-level highlighting ...
</policies>
### 🔄 azurerm_api_management_policy.global

| Attribute | Before | After |
| ----------- | -------- | ------- |
| xml_content | *(see below)* | *(see below)* |

Large values: xml_content (112 lines, 57 changed)

##### **xml_content:**

<pre><code><policies>
  <inbound>
<span style="background-color: #fff5f5; ...">-     <!-- Rate limiting policy --></span>
<span style="background-color: #fff5f5; ...">-     <rate-limit calls="100" renewal-period="60" /></span>
<span style="background-color: #f0fff4; ...">+     <!-- <span style="...">Rate limiting policy with increased limits</span> --></span>
<span style="background-color: #f0fff4; ...">+     <rate-limit calls="200" renewal-period="60" /></span>
    ...
</policies>
</code></pre>

Readable XML with character-level diff highlighting—every change is visible and reviewable.

Smart Formatting

  • Automatic Detection: Values longer than a threshold are automatically moved.
  • Collapsible Sections: Details are hidden by default to reduce noise.
  • Line-by-Line Diffs: Changes within large text blocks are highlighted.
  • Syntax Highlighting: JSON, YAML, and scripts are formatted for readability.

Configuration

Control the diff format for large values using the --render-target CLI option:

Command
# Default: azuredevops (HTML with character-level highlighting)
tfplan2md plan.json

# GitHub-compatible diff format (markdown code blocks)
tfplan2md plan.json --render-target github

Note: The --large-value-format flag has been deprecated. Use --render-target azuredevops instead of inline-diff, or --render-target github instead of standard-diff.

Learn More

Large value handling automatically detects and formats multi-line or long attribute values for better readability.