CtrlK
BlogDocsLog inGet started
Tessl Logo

nicholasjackson/terraform-plugin-framework

Comprehensive documentation and best practices for building Terraform providers with terraform-plugin-framework (v1.17.0). Covers providers, resources, schemas, types, validators, testing, and common pitfalls.

Overall
score

97%

Overview
Eval results
Files

index.mddocs/

Terraform Plugin Framework Guide

Comprehensive documentation for building Terraform providers with github.com/hashicorp/terraform-plugin-framework (v1.17.0).

What is terraform-plugin-framework?

terraform-plugin-framework is the recommended Go SDK for building Terraform providers. It provides a structured, type-safe approach to implementing providers, resources, data sources, functions, and other Terraform capabilities.

Key Benefits:

  • Type Safety: Strong typing throughout with compile-time checks
  • Modern Architecture: Protocol version 6 support (latest Terraform protocol)
  • Flexible Schema System: Rich attribute types, nested structures, validation
  • Testing Support: Integration with terraform-plugin-testing for acceptance tests
  • Extensibility: Custom types, validators, plan modifiers

When to Use:

  • Building new Terraform providers (recommended)
  • Need for complex nested schemas
  • Requirement for custom types or validation logic
  • Protocol version 6 features needed

When NOT to Use:

  • Maintaining existing terraform-plugin-sdk providers (migration effort required)
  • Very simple providers (framework may be overkill, but still recommended)

Version Compatibility

  • Framework: v1.17.0 (covered by this documentation)
  • Go: 1.24+ required
  • Terraform: 1.0+ (protocol v6 support)
  • Testing: terraform-plugin-testing v1.0+

Architecture Overview

Provider (metadata, config, resources, data sources, functions)
├── Resources (CRUD operations, state management)
│   └── Schema (attributes, validators, plan modifiers)
├── Data Sources (read operations)
│   └── Schema (attributes, validators)
├── Functions (custom Terraform functions)
└── Actions & Ephemeral Resources (session-scoped operations)

Protocol Flow:

  1. Terraform CLI starts provider as plugin subprocess
  2. Provider registers capabilities (resources, data sources, functions)
  3. Terraform calls provider methods via gRPC protocol
  4. Provider performs operations and returns results with diagnostics

Documentation Structure

This documentation is organized by framework capability:

Getting Started

  • Quick Start - Installation, first provider, when to use

Core Implementation

  • Provider - Provider interface, configuration, server setup
  • Resources - Resource CRUD, state management, import, lifecycle
  • Data Sources - Data source implementation, read patterns

Schema & Types

  • Schema System - Attributes, blocks, nesting, computed vs required
  • Type System - Framework types, conversions, null/unknown handling
  • Validators - Built-in validators, custom validators, cross-attribute
  • Plan Modifiers - UseStateForUnknown, RequiresReplace, custom

Advanced Features

  • Functions - Provider functions, parameters, returns, HCL usage
  • Advanced - Actions and ephemeral resources

Testing & Best Practices

  • Testing - Unit tests (testify/require), acceptance tests, patterns

Rules & Steering

The tile includes best practices rules (automatically loaded by agents):

  • Diagnostics: Always check diagnostics before proceeding
  • State Management: State consistency, UseStateForUnknown patterns
  • Schema Design: Schema design patterns, attribute modifiers
  • Testing Standards: testify/require requirements, test organization
  • Common Pitfalls: Consolidated gotchas from all areas

Common Patterns

Resource Implementation Pattern

// 1. Define resource type implementing resource.Resource
type PetResource struct {
    client *api.Client
}

// 2. Implement required methods
func (r *PetResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
    resp.TypeName = req.ProviderTypeName + "_pet"
}

func (r *PetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    // Define schema with attributes
}

func (r *PetResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    // Implement create logic
    // ALWAYS check resp.Diagnostics.HasError()
}

// Similar for Read, Update, Delete

Key Points:

  • Always check resp.Diagnostics.HasError() after operations
  • Use framework types (types.String, types.Int64, etc.) for attributes
  • State management via req.State.Get() and resp.State.Set()
  • Return early if diagnostics has errors

Schema Definition Pattern

schema.Schema{
    Attributes: map[string]schema.Attribute{
        "id": schema.StringAttribute{
            Computed: true,
            PlanModifiers: []planmodifier.String{
                stringplanmodifier.UseStateForUnknown(),
            },
        },
        "name": schema.StringAttribute{
            Required: true,
            Validators: []validator.String{
                stringvalidator.LengthAtLeast(1),
            },
        },
    },
}

Key Points:

  • Required, Optional, Computed determine attribute behavior
  • Use UseStateForUnknown() for computed attributes in Create
  • Add validators to enforce constraints
  • Use plan modifiers to control planning behavior

Common Pitfalls

⚠️ Not Checking Diagnostics: Always check resp.Diagnostics.HasError() before proceeding. Continuing after errors leads to panics.

⚠️ Missing UseStateForUnknown: Computed attributes without UseStateForUnknown() in Create operations show as "known after apply" unnecessarily, causing unnecessary replaces.

⚠️ Type Conversion Errors: Framework types (types.String) are not Go primitives. Use .ValueString(), .ValueInt64(), etc. for conversion. Check .IsNull() and .IsUnknown() first.

⚠️ State Management: Forgetting to call resp.State.Set() at the end of CRUD operations means state isn't saved, causing Terraform to think resource doesn't exist.

⚠️ Null vs Unknown: Null = explicitly no value (set to null). Unknown = value not yet known (depends on another resource). Handle both cases.

See Rules directory for comprehensive pitfalls and best practices.

External Resources

Official Documentation

  • HashiCorp Developer Docs
  • Package Reference
  • Scaffolding Template
  • Plugin Testing

Community

Related Tiles

  • Go Best Practices - General Go patterns (TDD, testify/require, mockery)
  • Reference for general Go idioms, this tile focuses on terraform-plugin-framework specifics

Quick Links

TopicDocumentation
First ProviderQuick Start
Provider SetupProvider
Resource CRUDResources
Schema DesignSchema System
Type SystemType System
ValidationValidators
Plan ModifiersPlan Modifiers
TestingTesting

Navigation

  • Next: Quick Start - Get started building your first provider
  • Up: README - Tile overview and installation

This documentation covers terraform-plugin-framework v1.17.0. For the latest version, see pkg.go.dev.

Install with Tessl CLI

npx tessl i nicholasjackson/terraform-plugin-framework@0.1.6

docs

advanced.md

data-sources.md

functions.md

index.md

plan-modifiers.md

provider.md

quick-start.md

resources.md

schema.md

testing.md

types.md

validators.md

README.md

tile.json