---
page_title: 'Plugin Development - Framework: List Nested Block'
description: >-
  Learn the list nested block type in the provider development framework.
---

# List Nested Block

<Tip>

Use [nested attribute types](/terraform/plugin/framework/handling-data/attributes#nested-attribute-types) instead of block types for new schema implementations. Block support is mainly for migrating legacy SDK-based providers.

</Tip>

List nested blocks are an ordered collection of structures mapping explicit attribute names to nested attribute and block definitions. Values are represented by a [list type](/terraform/plugin/framework/handling-data/types/list) in the framework, containing [object type](/terraform/plugin/framework/handling-data/types/object) of the mapped attributes and blocks.

In this Terraform configuration example, a list nested block named `example_block` is set to an ordered collection of an object value of `attr1` to `"value1"` and `attr2` to `123` and an object value of `attr1` to `"value2"` and `attr2` to `456`:

```hcl
resource "examplecloud_thing" "example" {
  example_block {
    attr1 = "value1"
    attr2 = 123
  }

  example_block {
    attr1 = "value2"
    attr2 = 456
  }
}
```

## Schema Definition

<Note>

Blocks can only be defined on schemas or nested blocks within a schema, not underneath an attribute or nested attribute.

</Note>

Use one of the following block types to directly add a list nested value to a [schema](/terraform/plugin/framework/handling-data/schemas) or [block type](/terraform/plugin/framework/handling-data/blocks):

| Schema Type | Attribute Type |
|-------------|----------------|
| [Data Source](/terraform/plugin/framework/data-sources) | [`schema.ListNestedBlock`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource/schema#ListNestedBlock) |
| [Provider](/terraform/plugin/framework/provider) | [`schema.ListNestedBlock`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider/schema#ListNestedBlock) |
| [Resource](/terraform/plugin/framework/resources) | [`schema.ListNestedBlock`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema#ListNestedBlock) |

The `NestedObject` field must be defined, which represents the [object value type](/terraform/plugin/framework/handling-data/types/object) of every element of the list.

In this example, a resource schema defines a top level list nested block named `example_block` with a required string attribute named `attr1` and optional integer attribute named `attr2`:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Blocks: map[string]schema.Block{
            "example_block": schema.ListNestedBlock{
                NestedObject: schema.NestedBlockObject{
                    Attributes: map[string]schema.Attribute{
                        "attr1": schema.StringAttribute{
                            Required: true,
                            // ... potentially other fields ...
                        },
                        "attr2": schema.Int64Attribute{
                            Optional: true,
                            // ... potentially other fields ...
                        },
                    },
                },
                // ... potentially other fields ...
            },
            // ... potentially other blocks ...
        },
    }
}
```

Its [value type](/terraform/plugin/framework/handling-data/types) would be represented as `types.List` of `types.Object` with a mapping of `attr1` to `types.String` and `attr2` to `types.Int64`.

A block type may itself contain further collection or nested attribute/block types, if necessary.

In this example, a resource schema defines a top level list nested block named `example_block` with a required list of strings attribute named `attr` and a single nested block named `block`:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Blocks: map[string]schema.Block{
            "example_block": schema.ListNestedBlock{
                NestedObject: schema.NestedBlockObject{
                    Attributes: map[string]schema.Attribute{
                        "attr": schema.ListAttribute{
                            ElementType: types.StringType,
                            Required: true,
                            // ... potentially other fields ...
                        },
                    },
                    Blocks: map[string]schema.Block{
                        "block": schema.ListNestedBlock{ /* ... */ },
                    },
                },
                // ... potentially other fields ...
            },
            // ... potentially other blocks ...
        },
    }
}
```

Its [value type](/terraform/plugin/framework/handling-data/types) would be represented as a `types.List` of `types.Object` with a mapping of `attr` to `types.List` of `types.String` and `block` to `types.Object`.

### Custom Types

You may want to build your own attribute value and type implementations to allow your provider to combine validation, description, and plan customization behaviors into a reusable bundle. This helps avoid duplication or reimplementation and ensures consistency. These implementations use the `CustomType` field in the attribute type.

Refer to [Custom Types](/terraform/plugin/framework/handling-data/types/custom) for further details on creating provider-defined types and values.

### Deprecation

Set the `DeprecationMessage` field to a practitioner-focused message for how to handle the deprecation. The framework will automatically raise a warning diagnostic with this message if the practitioner configuration contains a known value for the attribute. Terraform version 1.2.7 and later will raise a warning diagnostic in certain scenarios if the deprecated attribute value is referenced elsewhere in a practitioner configuration. The framework [deprecations](/terraform/plugin/framework/deprecations) documentation fully describes the recommended practices for deprecating an attribute or resource.

Some practitioner-focused examples of a deprecation message include:

- Configure `other_attribute` instead. This attribute will be removed in the next major version of the provider.
- Remove this attribute's configuration as it no longer is used and the attribute will be removed in the next major version of the provider.

### Description

The framework provides two description fields, `Description` and `MarkdownDescription`, which various tools use to show additional information about an attribute and its intended purpose. This includes, but is not limited to, [`terraform-plugin-docs`](https://github.com/hashicorp/terraform-plugin-docs) for automated provider documentation generation and [`terraform-ls`](https://github.com/hashicorp/terraform-ls) for Terraform configuration editor integrations.

### Plan Modification

<Highlight>

Only managed resources implement this concept.

</Highlight>

The framework provides two plan modification fields for managed resource attributes, `Default` and `PlanModifiers`, which define resource and attribute value planning behaviors. The resource [default](/terraform/plugin/framework/resources/default) and [plan modification](/terraform/plugin/framework/resources/plan-modification) documentation covers these features more in-depth.

#### Common Use Case Plan Modification

The [`listdefault`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault) package defines common use case `Default` implementations:

- [`StaticValue(types.List)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault#StaticValue): Define a static list default value for the attribute.

The [`listplanmodifier`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier) package defines common use case `PlanModifiers` implementations:

- [`RequiresReplace()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier#RequiresReplace): Marks the resource for replacement if the resource is being updated and the plan value does not match the prior state value.
- [`RequiresReplaceIf()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier#RequiresReplaceIf): Similar to `RequiresReplace()`, but also checks if a given function returns true.
- [`RequiresReplaceIfConfigured()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier#RequiresReplaceIfConfigured): Similar to `RequiresReplace()`, but also checks if the configuration value is not null.
- [`UseStateForUnknown()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier#UseStateForUnknown): Copies a known prior state value into the planned value. Use this when it is known that an unconfigured value will remain the same after a resource update.

### Validation

Set the `Validators` field to define [validation](/terraform/plugin/framework/validation#attribute-validation). This validation logic is ran in addition to any validation contained within a [custom type](#custom-types).

#### Common Use Case Validators

HashiCorp provides the additional [`terraform-plugin-framework-validators`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework-validators) Go module which contains validation logic for common use cases. The [`listvalidator`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework-validators/listvalidator) package within that module has list attribute validators such as defining conflicting attributes.

## Accessing Values

The [accessing values](/terraform/plugin/framework/handling-data/accessing-values) documentation covers general methods for reading [schema](/terraform/plugin/framework/handling-data/schemas) (configuration, plan, and state) data, which is necessary before accessing an attribute value directly. The [list type](/terraform/plugin/framework/handling-data/types/list#accessing-values) documentation covers methods for interacting with the attribute value itself.

## Setting Values

The [list type](/terraform/plugin/framework/handling-data/types/list#setting-values) documentation covers methods for creating or setting the appropriate value. The [writing data](/terraform/plugin/framework/handling-data/writing-state) documentation covers general methods for writing [schema](/terraform/plugin/framework/handling-data/schemas) (plan and state) data, which is necessary afterwards.
