# Customize Terraform Properties

## Remap API Property to Terraform Attribute Name

The `x-speakeasy-name-override` annotation adjusts the Terraform attribute name within a resource while remapping all the API data handling internally. This is useful, for example, to standardize differing API property names across operations to a single attribute name.

```yaml
unique_id:
  type: string
  x-speakeasy-name-override: id
```

The annotation also has other [SDK customization capabilities](/docs/customize-sdks/methods), however, those are generally unnecessary for Terraform providers as the generated Go SDK is internal to the provider code.

## Align API Parameter With Terraform Property

The `x-speakeasy-match` annotation adjusts the API parameter name to align with a Terraform state property. If mismatches occur, a generation error will highlight appropriate root-level properties for accurate mapping.

```yaml
paths:
  /pet/{petId}:
    delete:
      parameters:
        - name: petId
          x-speakeasy-match: id
      x-speakeasy-entity-operation: Pet#delete
```

## Customize Status Codes for Missing Resources

By default, Terraform removes a resource from state when a Read operation returns an HTTP 404 Not Found status code. However, some APIs use different status codes to indicate a resource is missing or has been deleted, such as 403 Forbidden or 410 Gone.

The `x-speakeasy-entity-missing-codes` extension allows you to specify additional HTTP status codes that should trigger resource removal during Read operations. Apply this extension at the operation level on Read endpoints.

```yaml
paths:
  "/pet/{petId}":
    get:
      x-speakeasy-entity-operation: Pet#read
      x-speakeasy-entity-missing-codes:
        - 403
        - 410
      parameters:
        - name: petId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
        "403":
          description: Forbidden - resource has been deleted
        "404":
          description: Not found
        "410":
          description: Gone - resource permanently deleted
```

When any of the specified status codes are returned during a Read operation, Terraform will automatically remove the resource from state and propose recreation on the next plan. The 404 status code is always checked by default, so you only need to specify additional codes.

## Property Defaults

Setting a property default value that matches your API responses when unconfigured will enhance the Terraform plan to include the known value, rather than propagate the value as unknown `(known after apply)` during creation and updates.

Speakeasy generation automatically adds a Terraform schema attribute default with OAS `default` value, for each of the following OAS types:

| OAS Schema Type | OAS default Support                                                      |
| --------------- | ------------------------------------------------------------------------ |
| `array`         | Partial (`[]` and values of `boolean`/`number`/`string` item types only) |
| `boolean`       | Yes                                                                      |
| `map`           | No                                                                       |
| `number`        | Yes                                                                      |
| `object`        | Partial (`null` only)                                                    |
| `oneOf`         | No                                                                       |
| `string`        | Yes                                                                      |

### Custom Defaults

For unsupported or advanced use cases, the [Terraform SDK supports calling schema-defined custom default logic](https://developer.hashicorp.com/terraform/plugin/framework/resources/default#custom-default-implementations). Create the custom code implementing the [Terraform type-specific `resource/schema/defaults` package interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults) in any code location and use the OAS `x-speakeasy-terraform-custom-default` extension to reference that implementation in the schema definition.

In this example, a custom string default implementation is created in `internal/customdefaults/example.go`:

```go
package customdefaults

import (
  "context"

  "github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults"
  "github.com/hashicorp/terraform-plugin-framework/types"
)

func Example() defaults.String {
  return exampleDefault{}
}

type exampleDefault struct{}

func (d exampleDefault) Description(ctx context.Context) string {
  return "Example custom default description"
}

func (d exampleDefault) MarkdownDescription(ctx context.Context) string {
  return "Example custom default description"
}

func (d exampleDefault) DefaultString(ctx context.Context, req defaults.StringRequest, resp *defaults.StringResponse) {
  resp.PlanValue = types.StringValue("example custom default")
}
```

With the following OAS configuration on the target property:

```yaml
example:
  type: string
  x-speakeasy-terraform-custom-default:
    imports:
      - github.com/examplecorp/terraform-provider-examplecloud/internal/customdefaults
    schemaDefinition: customdefaults.Example()
```

The `imports` configuration is optional if the custom code is within the `internal/provider` package and does not require additional imports.

## Hide Sensitive Properties

Properties marked as `x-speakeasy-param-sensitive` will be concealed from the console output of Terraform. This helps to ensure the confidentiality of sensitive data within Terraform operations.

```yaml
components:
  schemas:
    Pet:
      type: object
      properties:
        name:
          type: string
        secret:
          type: string
          x-speakeasy-param-sensitive: true
```

## Write only

Mark a schema attribute as a [write only argument](https://developer.hashicorp.com/terraform/plugin/framework/resources/write-only-arguments) (`WriteOnly: true` in the schema definition) with the `x-speakeasy-terraform-write-only` extension. Write only functionality prevents values from ever being exposed in plan or state data as a more complete secret value solution over sensitive attributes.

<Callout title="Warning" type="warning">
  Write only functionality is only supported in Terraform/OpenTofu 1.11 and
  later. Using it on earlier versions of Terraform/OpenTofu will result in a
  configuration error.
</Callout>

```yaml
components:
  schemas:
    Pet:
      type: object
      properties:
        name:
          type: string
        secret:
          type: string
          x-speakeasy-terraform-write-only: true
```

## Deprecation

Add OAS `deprecated: true` within a property to automatically return a warning diagnostic with a generic deprecation message when the property is configured in Terraform. Customize the messaging with the OAS `x-speakeasy-deprecation-message` extension.

<Callout title="Info" type="info">
  Terraform always returns deprecation warnings for configured properties, but
  has limitations for displaying these warnings with response-only properties
  that are referenced elsewhere in the configuration. [Terraform Feature
  Request](https://github.com/hashicorp/terraform/issues/7569)
</Callout>

In this example, Terraform will display a warning diagnostic with `Custom deprecation message` if the property is configured:

```yaml
example:
  type: string
  deprecated: true
  x-speakeasy-deprecation-message: Custom deprecation message
```

## Exclude Property From Terraform State

When `x-speakeasy-terraform-ignore: true`, this extension ensures the specified property and any interactions involving it are omitted from Terraform's state management.

<Callout title="Info" type="info">
  This extension completely suppresses the property from the Terraform state. If
  you want to suppress a specific operation, use `x-speakeasy-ignore: true` to
  omit the operation from the annotated CRUD method. For example, if a field is
  present in both the `CREATE` and `READ` response bodies, omitting it from the
  `READ` response body will turn off drift detection for that field. The field
  will remain in the `CREATE` response body and the Terraform state.
</Callout>

```yaml
components:
  schemas:
    Pet:
      x-speakeasy-entity: Pet
      type: object
      properties:
        optionalMetadata:
          x-speakeasy-terraform-ignore: true
          type: string
        name:
          type: string
      required:
        - name
```

```hcl
resource "petstore_pet" "mypet" {
  name = "myPet"
  # Attempting to set an ignored parameter results in an error
  # optionalMetadata = true
}
```

Use `x-speakeasy-terraform-ignore: schema` to prevent generation errors when the property is required across API operations for the same Terraform operation and it should only be removed from the Terraform schema/state.

## Custom Types

Set the `x-speakeasy-terraform-custom-type` extension to switch a property from the terraform-plugin-framework base type (e.g. `types.String`) to a [custom type](https://developer.hashicorp.com/terraform/plugin/framework/handling-data/types/custom). Custom types typically include format-specific validation logic (such as a baked-in regular expression) or semantic equality handling to prevent unintentional value differences (such as ignoring inconsequential whitespace).

The following terraform-plugin-framework base types are supported for custom types:

- `Bool`
- `Float32`
- `Float64`
- `Int32`
- `Int64`
- `List`
- `Map`
- `Set`
- `String`

In this example, the `ipv4_address` string property will use the custom `iptypes.IPv4Address` type:

```yaml
ipv4_address:
  type: string
  x-speakeasy-terraform-custom-type:
    imports:
      - github.com/hashicorp/terraform-plugin-framework-nettypes/iptypes
    schemaType: "iptypes.IPv4AddressType{}"
    valueType: iptypes.IPv4Address
```

## Allow JSON String Attributes

When `contentMediaType: application/json` is set on a property, it is automatically configured as a JSON-encoded string attribute with validation and semantic equality (e.g. ignore whitespace difference) behaviors. The JSON-encoded string is the value sent to and from the API.

To explicitly convert the Terraform schema to use a JSON-encoded string attribute when the OpenAPI Specification schema has a differing type, set the `x-speakeasy-type-override` extension to `any`. This allows inlining the specification of the attribute's value, accommodating attributes with variable or dynamic structures.

```yaml
components:
  schemas:
    Pet:
      x-speakeasy-entity: Pet
      type: object
      properties:
        deep:
          x-speakeasy-type-override: any
          type: object
          properties:
            object:
              type: object
              additionalProperties: true
              properties:
                in:
                  type: object
                  properties:
                    here:
                      type: string
        name:
          type: string
      required:
        - name
```

```hcl
resource "petstore_pet" "mypet" {
  name = "myPet"
  deep = jsonencode({
    object = {
      with = "anything"
      defined = true
    }
  })
}
```

## Suppress Unnecessary Plan Changes

Setting the `x-speakeasy-param-suppress-computed-diff` to true suppresses unnecessary Terraform plan changes for computed attributes that are not definitively known until after application. This is useful in scenarios where computed attributes frequently cause spurious plan changes.

```yaml
components:
  schemas:
    Pet:
      x-speakeasy-entity: Pet
      type: object
      properties:
        name:
          type: string
        status:
          x-speakeasy-param-suppress-computed-diff: true
          type: string
```

<Callout title="Warning" type="warning">
  Applying this modifier when `x-speakeasy-entity-operation: my_resource#read`
  is not defined may result in drift between the Terraform plan and remote state
  should updates to attributes happen outside of Terraform changes. Please only
  apply this when necessary.
</Callout>

## Filter Data Resource Results by Response Values

Some list API endpoints do not support server-side filtering. The `x-speakeasy-response-filter` extension enables client-side filtering of list API responses in [data resources](https://developer.hashicorp.com/terraform/language/data-sources), allowing Terraform users to narrow results by matching property values.

When applied to a response property, the generated data resource schema promotes that property to an optional, configurable attribute. If a user provides a value for a filter attribute, the generated provider filters the API response array on the client side, returning only items where the property matches the configured value.

<Callout title="Info" type="info">
  This extension only applies to data resources that read from list API
  endpoints returning arrays. Only top-level primitive fields (`string`,
  `number`, `boolean`, `integer`) are supported as filter properties.
</Callout>

### Basic usage

Mark response properties with `x-speakeasy-response-filter: true` to make them available as filter attributes in the data resource:

```yaml
components:
  schemas:
    Pet:
      x-speakeasy-entity: Pets
      type: object
      properties:
        name:
          type: string
          x-speakeasy-response-filter: true
        species:
          type: string
          x-speakeasy-response-filter: true
        id:
          type: integer
        age:
          type: integer
```

With the corresponding list operation:

```yaml
paths:
  /pets:
    get:
      summary: List all pets
      x-speakeasy-entity-operation: Pets#read
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Pet"
```

Terraform users can then filter the data resource results:

```hcl
data "example_pets" "dogs" {
  name    = "Buddy"
  species = "dog"
}
```

The generated provider fetches all pets from the API and returns only items where `name` equals `"Buddy"` and `species` equals `"dog"`.

### Array response wrapping

For APIs where the response is wrapped in an object, the extension works with the array items. Filter fields are automatically hoisted from the array item level to the data resource root for a flat configuration experience:

```yaml
components:
  schemas:
    PetList:
      x-speakeasy-entity: Pets
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                x-speakeasy-response-filter: true
              id:
                type: integer
```

The Terraform configuration remains flat regardless of the API response structure:

```hcl
data "example_pets" "my_pet" {
  name = "Buddy"
}
```
