Skip to content
Development
Skill

/provider-resources

Implement Terraform Provider resources and data sources using the Plugin Framework: CRUD operations, schema design, plan modifiers and validators, not-found handling, waiters for eventually consistent APIs, import support, resource design principles, and required acceptance test

From plugin
hashicorp-agent-skills
86420 skills
Install
$ npx -y skills add hashicorp/agent-skills --skill provider-resources --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/provider-resources

Context preview

The summary Claude sees to decide when to auto-load this skill.

Implement Terraform Provider resources and data sources using the Plugin Framework: CRUD operations, schema design, plan modifiers and validators, not-found handling, waiters for eventually consistent APIs, import support, resource design principles, and required acceptance test

SKILL.md

provider-resources.SKILL.md
name: provider-resources
description: >-
  Implement Terraform Provider resources and data sources using the Plugin
  Framework: CRUD operations, schema design, plan modifiers and validators,
  not-found handling, waiters for eventually consistent APIs, import support,
  resource design principles, and required acceptance test coverage. Use when
  adding or changing a resource or data source, deciding whether an API
  concept should be a resource, wiring a resource to the provider's
  configured client, handling drift or resource-not-found, or reviewing a
  resource implementation before submission.
license: MPL-2.0
metadata:
  lifecycle-status: active
  copyright: Copyright IBM Corp. 2026
  version: "0.0.1"

Terraform Provider Resources Implementation Guide

Overview

This guide covers developing Terraform Provider resources and data sources. Resources represent infrastructure objects that Terraform manages through Create, Read, Update, and Delete (CRUD) operations.

**Use the [Plugin Framework](https://developer.hashicorp.com/terraform/plugin/framework) for all net-new resources and data sources.** Plugin SDKv2 is for maintaining resources that already exist on it; do not write new code against it. A provider can serve both during migration by muxing ([terraform-plugin-mux](https://developer.hashicorp.com/terraform/plugin/mux)), so adopting the Framework never requires a big-bang rewrite. To tell which mode an existing provider is in, check `go.mod`: `terraform-plugin-mux` present means it serves both SDKv2 and Framework code; only `terraform-plugin-sdk/v2` means SDKv2-only; only `terraform-plugin-framework` means Framework-only. Be cautious about *migrating* existing SDKv2 resources: the Framework distinguishes null from zero values, so naive migrations change behavior for existing users (use the `provider-framework-migration` skill, if available).

**References** (load when needed):

  • `references/design-principles.md` — what should (and should not) become a

resource; data source semantics; relationship and async-task modeling

  • `references/retries-and-waiters.md` — eventual consistency, retry

patterns, and status/wait function structure

File Structure

Most providers keep every resource in a single package:

internal/provider/
├── provider.go                  # Provider schema + Configure
├── widget_resource.go           # Resource implementation
├── widget_resource_test.go      # Acceptance tests
├── widget_data_source.go        # Data source (if applicable)
└── widget_data_source_test.go

Large multi-service providers (e.g. terraform-provider-aws) split into `internal/service/<service>/` packages instead, with an idiomatic file taxonomy worth adopting once a package grows: `consts.go`, `find.go` (finders), `status.go` (status functions), `wait.go` (waiters), `sweep.go` (test sweepers), `exports_test.go`.

Documentation lives in `docs/` and is generated with `tfplugindocs`:

docs/
├── resources/<name>.md          # generated; optional <name>.md.tmpl template
└── data-sources/<name>.md

(Hand-written `website/docs/r/*.html.markdown` trees exist in some older, large providers — follow the target repo's convention when editing one.)

Resource Structure

A Framework resource is a struct holding the API client, with interface assertions making the implemented behaviors explicit:

var (
    _ resource.Resource                = &widgetResource{}
    _ resource.ResourceWithConfigure   = &widgetResource{}
    _ resource.ResourceWithImportState = &widgetResource{}
)

func NewWidgetResource() resource.Resource {
    return &widgetResource{}
}

type widgetResource struct {
    client *examplecloud.Client
}

func (r *widgetResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
    resp.TypeName = req.ProviderTypeName + "_widget"
}

// Configure receives the client the provider built in its own Configure.
func (r *widgetResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
    if req.ProviderData == nil {
        return // provider not yet configured (e.g. validation phase)
    }
    client, ok := req.ProviderData.(*examplecloud.Client)
    if !ok {
        resp.Diagnostics.AddError(
            "Unexpected Resource Configure Type",
            fmt.Sprintf("Expected *examplecloud.Client, got: %T.", req.ProviderData),
        )
        return
    }
    r.client = client
}

func (r *widgetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "name": schema.StringAttribute{
                Required: true,
                PlanModifiers: []planmodifier.String{
                    stringplanmodifier.RequiresReplace(),
                },
                Validators: []validator.String{
                    stringvalidator.LengthBetween(1, 255),
                },
            },
            "id": schema.StringAttribute{
                Computed: true,
                PlanModifiers: []planmodifier.String{
                    stringplanmodifier.UseStateForUnknown(),
                },
            },
        },
    }
}

How the provider's `Configure` produces that client — schema, credential resolution, validation — is covered by the `provider-configuration` skill (if available).

**On `id`:** SDKv2 required a magic `id` attribute; the Framework does not. If the API has its own identifier, expose it under its real meaning and do not add a second, redundant `id`. Only keep `id` when it *is* the API's identifier (as above).

CRUD Operations

Create

func (r *widgetResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    var data widgetResourceModel
    resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
    if resp.Diagnostics.HasError() {
        return
    }

    inp
Read more
Ships withhashicorp-agent-skills

HashiCorp Agent Skills for Terraform and Packer. See SKILLS.md for the complete catalog and lifecycle status of each Skill. Legal note: Your use of a third-party MCP client or LLM is subject solely to that provider's terms.

Get the whole plugin
Stats
864
Stars
126
Forks
Active
Maintenance
HCL
Language
MPL-2.0
License
10d ago
Last commit
10mo ago
Created

Repo: hashicorp/agent-skills

Other skills on hashicorp-agent-skills.