Skip to content
Development
Skill

/provider-framework-migration

Migrate Terraform provider resources and data sources from Plugin SDKv2 to the Plugin Framework: muxing both plugins in one provider (terraform-plugin-mux, tf5to6server), per-resource migration workflow, SDKv2-to-Framework schema mapping (ForceNew, ValidateFunc,

From plugin
hashicorp-agent-skills
86420 skills
Install
$ npx -y skills add hashicorp/agent-skills --skill provider-framework-migration --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-framework-migration

Context preview

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

Migrate Terraform provider resources and data sources from Plugin SDKv2 to the Plugin Framework: muxing both plugins in one provider (terraform-plugin-mux, tf5to6server), per-resource migration workflow, SDKv2-to-Framework schema mapping (ForceNew, ValidateFunc,

SKILL.md

provider-framework-migration.SKILL.md
name: provider-framework-migration
description: >-
  Migrate Terraform provider resources and data sources from Plugin SDKv2 to
  the Plugin Framework: muxing both plugins in one provider
  (terraform-plugin-mux, tf5to6server), per-resource migration workflow,
  SDKv2-to-Framework schema mapping (ForceNew, ValidateFunc,
  DiffSuppressFunc, Default, Timeouts, blocks), null-vs-zero-value
  behavioral traps, and state-compatibility verification. Use when
  converting or translating SDKv2 resources to the Framework, setting up a
  muxed provider server, deciding whether a resource should be migrated at
  all, or debugging plan diffs and state errors that appeared after a
  migration.
license: MPL-2.0
metadata:
  lifecycle-status: active
  copyright: Copyright IBM Corp. 2026
  version: "0.0.1"

Migrating from Plugin SDKv2 to the Plugin Framework

The Plugin Framework is required for net-new resources and data sources; SDKv2 is maintenance-only. Migration is **per-resource and incremental**: a muxed provider serves SDKv2 and Framework implementations side by side, so you never need a big-bang rewrite. This skill covers the mux setup, the per-resource workflow, and the behavioral traps that turn a mechanical translation into a silent breaking change.

**Reference** (load when needed):

  • `references/schema-mapping.md` — the full SDKv2 → Framework translation

table with code pairs

Official guide: [Framework migration](https://developer.hashicorp.com/terraform/plugin/framework/migrating).

Decide Whether to Migrate at All

Migration has real risk and little user-visible payoff, so triage first:

  • **Do not migrate complex or heavily-used resources** without a driving

need (a Framework-only feature, a bug that SDKv2 cannot fix). The two SDKs differ behaviorally — most importantly around null versus zero values — and those differences surface as breaking changes for existing users. This is the standing policy in large providers like terraform-provider-aws.

  • **Simple resources migrate safely**: flat schemas, no `DiffSuppressFunc`,

no `CustomizeDiff`, no `StateFunc`, no complex nested blocks.

  • New capabilities never require migrating old code — mux and write the new

resource in the Framework alongside the old ones.

To tell what mode a provider is in, check `go.mod`: `terraform-plugin-mux` present means it already serves both; only `terraform-plugin-sdk/v2` means SDKv2-only (mux setup is your first step); only `terraform-plugin-framework` means the migration is done.

Step 1: Mux the Provider

Combine both plugin servers in `main.go`. Serving protocol version 6 requires upgrading the SDKv2 server with `tf5to6server` (protocol 6 needs Terraform CLI >= 1.0; if you must support 0.12+, mux at protocol 5 with `tf6to5server`/`tf5muxserver` instead — but the Framework provider then cannot use protocol-6-only features like nested attributes):

package main

import (
    "context"
    "flag"
    "log"

    "github.com/hashicorp/terraform-plugin-framework/providerserver"
    "github.com/hashicorp/terraform-plugin-go/tfprotov6"
    "github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server"
    "github.com/hashicorp/terraform-plugin-mux/tf5to6server"
    "github.com/hashicorp/terraform-plugin-mux/tf6muxserver"

    "example.org/terraform-provider-examplecloud/internal/provider"
    sdkprovider "example.org/terraform-provider-examplecloud/internal/sdkprovider"
)

func main() {
    var debug bool
    flag.BoolVar(&debug, "debug", false, "run with support for debuggers")
    flag.Parse()

    ctx := context.Background()

    upgradedSDKServer, err := tf5to6server.UpgradeServer(
        ctx,
        sdkprovider.Provider().GRPCProvider,
    )
    if err != nil {
        log.Fatal(err)
    }

    providers := []func() tfprotov6.ProviderServer{
        providerserver.NewProtocol6(provider.New(version)()),
        func() tfprotov6.ProviderServer { return upgradedSDKServer },
    }

    muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)
    if err != nil {
        log.Fatal(err)
    }

    var serveOpts []tf6server.ServeOpt
    if debug {
        serveOpts = append(serveOpts, tf6server.WithManagedDebug())
    }

    err = tf6server.Serve("registry.terraform.io/example/examplecloud",
        muxServer.ProviderServer, serveOpts...)
    if err != nil {
        log.Fatal(err)
    }
}

Mux requirements that bite in practice:

  • **Provider schemas must match exactly** across both plugins — same

provider-level attributes, same types, same descriptions. Keep one source of truth for the provider configuration and mirror it.

  • **Each resource and data source may exist in only one** of the two

plugins. Migration's final step is deleting the SDKv2 registration.

  • If publishing to the Registry with protocol 6, set

`"metadata": {"protocol_versions": ["6.0"]}` in `terraform-registry-manifest.json`.

Step 2: Baseline Before You Touch Anything

The migrated resource must be indistinguishable to users. Prove it with tests that exist *before* the migration:

1. Ensure the resource has passing acceptance coverage: `_basic` with an import step (`ImportStateVerify: true`), `_disappears`, and per-attribute update tests. If coverage is missing, write it against the SDKv2 implementation first — these tests are the migration's acceptance criteria and must pass **unchanged** afterward. 2. Note behaviors tests don't capture: attribute defaults, what happens when optional attributes are omitted (null vs `""`/`0`/`false` is about to matter), and any `DiffSuppressFunc`/`StateFunc` normalization.

Step 3: Port the Resource

Translate schema and CRUD using the mapping table in `references/schema-mapping.md`. The rules that prevent breaking changes:

  • **Blocks stay blocks.** An SDKv2 `Elem: &schema.Resource{...}` written as

`block { ... }` syntax in user configs must become a Framework **Block** (`schema.ListNestedBlock`/`SetNestedBlock`) — converting it to

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.