Provider Actions
Implement Terraform Provider actions using the Plugin Framework. Use when developing imperative operations that execute at lifecycle events (before/after create, update, destroy).
- Skill ID
- hashicorp/agent-skills/provider-actions
- Publisher
- hashicorp
- Repository
- agent-skills
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
hashicorp/agent-skills/provider-actionsInstalls these files- SKILL.md
What this skill tells the agent
Terraform Provider Actions Implementation Guide
Overview
Terraform Actions enable imperative operations during the Terraform lifecycle. Actions are experimental features that allow performing provider operations at specific lifecycle events (before/after create, update, destroy).
References:
First Action Setup
When adding the first action to a provider that has never had one, several one-time scaffolding steps are required:
- Implement `ProviderWithActions` — add an
Actions()method to the provider that returns[]func() action.Action. - Set `ActionData` in `Configure` — the provider's
Configuremethod must setresp.ActionData = valongside the existingResourceData,DataSourceData, andEphemeralResourceDataassignments. - Create `ActionWithConfigure` base type — if the provider uses embedded base types (e.g.
ResourceWithConfigure), create an equivalentActionWithConfiguretype implementingaction.ConfigureRequest/action.ConfigureResponse. - Action-schema helper variants — if the provider injects common schema attributes (e.g.
namespace) via helper functions, action-schema variants are needed sinceaction/schematypes differ fromresource/schematypes.
File Structure
Most providers keep actions alongside resources in the provider package:
internal/provider/
├── <action_name>_action.go # Action implementation
└── <action_name>_action_test.go # Action tests(Large multi-service providers use internal/service/<service>/ packages instead — follow the target repository's layout.)
Documentation lives with the other generated docs:
docs/actions/
└── <action_name>.md # User-facing documentation(Some older, large providers hand-write website/docs/actions/<name>.html.markdown instead — match the repo.)
Action Schema Definition
Actions use the Terraform Plugin Framework with a standard schema pattern:
func (a *actionType) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
// Required configuration parameters
"resource_id": schema.StringAttribute{
Required: true,
Description: "ID of the resource to operate on",
},
// Optional parameters with defaults
"timeout": schema.Int64Attribute{
Optional: true,
Description: "Operation timeout in seconds",
Default: int64default.StaticInt64(1800),
Computed: true,
},
},
}
}Common Schema Issues
Pay special attention to the schema definition - common issues after a first draft:
- Type Mismatches
- Model structs use
types.String/types.Int64and schemas usetypes.StringTypefromgithub.com/hashicorp/terraform-plugin-framework/types— don't mix in types from other packages - Some large providers layer their own custom type package on top (e.g. terraform-provider-aws's internal
fwtypes); inside such a repo, follow its convention consistently instead of the plain types
- List/Map Element Types ```go // WRONG - missing ElementType "items": schema.ListAttribute{ Optional: true, }
// CORRECT "items": schema.ListAttribute{ Optional: true, ElementType: types.StringType, }
3. **Computed vs Optional**
- Attributes with defaults must be both `Optional: true` and `Computed: true`
- Don't mark action inputs as `Computed` unless they have defaults
4. **Validator Imports**// Ensure proper imports "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
5. **Region/Provider Attribute** (multi-region providers, e.g. AWS)
- Use the provider's shared region handling when it has one
- Don't manually re-define provider-level configuration in an action schema
6. **Nested Attributes**
- Use appropriate nested object types for complex structures
- Ensure nested types are properly defined
### Schema Validation Checklist
Before submitting, verify:
- [ ] All attributes have descriptions
- [ ] List/Map attributes have ElementType defined
- [ ] Validators are imported and applied correctly
- [ ] Model struct uses correct framework types
- [ ] Optional attributes with defaults are marked Computed
- [ ] Code compiles without type errors
- [ ] Run `go build` to catch type mismatches
## Action Invoke Method
The Invoke method contains the action logic:
func (a actionType) Invoke(ctx context.Context, req action.InvokeRequest, resp action.InvokeResponse) { var data actionModel resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return }
// a.client was stored by Configure (from req.ProviderData), the same // pattern resources use. resp.SendProgress(action.InvokeProgressEvent{Message: "Starting operation..."})
// Implement action logic with error handling // Use context for timeout management // Poll for completion if async operation
resp.SendProgress(action.InvokeProgressEvent{Message: "Operation completed"}) }
## Key Implementation Requirements
### 1. Progress Reporting
- Use `resp.SendProgress(action.InvokeProgressEvent{...})` for real-time updates
- Provide meaningful progress messages during long operations
- Update progress at key milestones
- Include elapsed time for long operations
### 2. Timeout Management
- Always include configurable timeout parameter (default: 1800s)
- Use `context.WithTimeout()` for API calls
- Handle timeout errors gracefully
- Validate timeout ranges (typically 60-7200 seconds)
### 3. Error Handling
- Add diagnostics with `resp.Diagnostics.AddError()`
- Provide clear error messages with context
- Include API error details when relevant
- Map provider error types to user-friendly messages
- Document all possible error cases
Example error handling:// Handle specific errors var notFound *types.ResourceNotFoundException if errors.As(err, ¬Found) { resp.Diagnostics.AddError( "Resource Not Found", fmt.Sprintf("Resource %s was not found", resourceID), ) return }
// Generic error handling resp.Diagnostics.AddError( "Operation Failed", fmt.Sprintf("Could not complete operation for %s: %s", resourceID, err), )
### 4. Provider SDK Integration
- Use the API client stored at Configure time (`a.client`), shared with
resources and data sources
- Handle pagination for list operations
- Implement retry logic for transient failures
- Use appropriate error types
### 5. Parameter Validation
- Use framework validators for input validation
- Validate resource existence before operations
- Check for conflicting parameters
- Validate against provider naming requirements
### 6. Polling and Waiting
For operations that require waiting for completion, poll on a ticker under
a context deadline, reporting progress as you go. (Alternatively use
`retry.StateChangeConf` from
`github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry`, the same waiter
primitive resources use.)
ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel()
ticker := time.NewTicker(5 * time.Second) defer ticker.Stop()
// Poll fast, report slow: progress events cross the plugin protocol, so // throttle them instead of emitting one per poll. start := time.Now() var lastProgress time.Time for { res, err := findResource(ctx, a.client, id) if err != nil {
More from hashicorp
Use this skill in a project
Open any RiverX project, search the Skills panel for hashicorp/agent-skills/provider-actions, and install it in one click.
