• Overview
    • Enforce Policy as Code
    • Infrastructure as Code
    • Inject Secrets into Terraform
    • Integrate with Existing Workflows
    • Manage Kubernetes
    • Manage Virtual Machine Images
    • Multi-Cloud Deployment
    • Network Infrastructure Automation
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
  • Registry
  • Tutorials
    • About the Docs
    • Intro to Terraform
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
    • Terraform Tools
    • CDK for Terraform
    • Glossary
  • Community
GitHubTerraform Cloud
Download

    SDKv2

  • Overview
  • Tutorials: Custom Providers
    • Overview
    • Schema Types
    • Schema Behaviors
    • Schema Methods
    • Overview
    • Customizing Differences
    • Import
    • Retries and Customizable Timeouts
    • State Migration
  • Debugging Providers
    • Compatibility with Terraform 0.12
    • Switching to the standalone SDK
    • v2 Upgrade Guide
    • Overview
    • Naming
    • Depending on Providers
    • Deprecations, Removals, and Renames
    • Detecting Drift
    • Handling Sensitive Data
    • Testing Patterns
    • Versioning and Changelog
    • Writing Non-Go Providers
    • Overview
      • Overview
      • Test Cases
      • Test Steps
      • Sweepers
    • Testing API
    • Testing Patterns
    • Unit Testing
  • Other Plugin Docs

  • Plugin Development
  • Framework
  • Logging
  • Combining and Translating
Type '/' to Search

»Resources - Customizing Differences

Terraform tracks the state of provisioned resources in its state file, and compares the user-passed configuration against that state. When Terraform detects a discrepancy, it presents the user with the differences between the configuration and the state.

Sometimes determining the differences between state and configuration requires special handling, which can be managed with the CustomizeDiff function.

CustomizeDiff is passed a *schema.ResourceDiff. This is a structure similar to schema.ResourceData — it lacks most write functions (like Set), but adds some functions for working with the difference, such as SetNew, SetNewComputed, and ForceNew.

NOTE: CustomizeDiff does not currently support computed/"known after apply" values from other resource attributes.

Any function can be provided for difference customization. For the majority of simple cases, we recommend that you first try to compose the behavior using the customdiff helper package, which allows for a more declarative configuration. However, for highly custom requirements, a custom-made function is usually easier and more maintainable than working around the helper's limitations.

package example

import (
    "fmt"

    "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
    "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceExampleInstance() *schema.Resource {
    return &schema.Resource{
        Create: resourceExampleInstanceCreate,
        Read:   resourceExampleInstanceRead,
        Update: resourceExampleInstanceUpdate,
        Delete: resourceExampleInstanceDelete,

        Schema: map[string]*schema.Schema{
            "size": {
                Type:     schema.TypeInt,
                Required: true,
            },
        },
        CustomizeDiff: customdiff.All(
            customdiff.ValidateChange("size", func (old, new, meta interface{}) error {
                // If we are increasing "size" then the new value must be
                // a multiple of the old value.
                if new.(int) <= old.(int) {
                    return nil
                }
                if (new.(int) % old.(int)) != 0 {
                    return fmt.Errorf("new size value must be an integer multiple of old value %d", old.(int))
                }
                return nil
            }),
            customdiff.ForceNewIfChange("size", func (old, new, meta interface{}) bool {
                // "size" can only increase in-place, so we must create a new resource
                // if it is decreased.
                return new.(int) < old.(int)
            }),
       ),
    }
}
package example

import (
    "fmt"

    "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
    "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceExampleInstance() *schema.Resource {
    return &schema.Resource{
        Create: resourceExampleInstanceCreate,
        Read:   resourceExampleInstanceRead,
        Update: resourceExampleInstanceUpdate,
        Delete: resourceExampleInstanceDelete,

        Schema: map[string]*schema.Schema{
            "size": {
                Type:     schema.TypeInt,
                Required: true,
            },
        },
        CustomizeDiff: customdiff.All(
            customdiff.ValidateChange("size", func (old, new, meta interface{}) error {
                // If we are increasing "size" then the new value must be
                // a multiple of the old value.
                if new.(int) <= old.(int) {
                    return nil
                }
                if (new.(int) % old.(int)) != 0 {
                    return fmt.Errorf("new size value must be an integer multiple of old value %d", old.(int))
                }
                return nil
            }),
            customdiff.ForceNewIfChange("size", func (old, new, meta interface{}) bool {
                // "size" can only increase in-place, so we must create a new resource
                // if it is decreased.
                return new.(int) < old.(int)
            }),
       ),
    }
}

In this example we use the helpers to ensure the size can only be increased to multiples of the original size, and that if it is ever decreased it forces a new resource. The customdiff.All helper will run all the customization functions, collecting any errors as a multierror. To have the functions short-circuit on error, please use customdiff.Sequence.

github logoEdit this page
  • Overview
  • Docs
  • Extend
  • Privacy
  • Security
  • Press Kit
  • Consent Manager