When to Build a Custom Provider
Decision Framework
Building a custom Terraform provider is a significant investment. Before starting, carefully evaluate whether a provider is the right solution for your needs.
This chapter provides a structured decision framework, explores alternatives, and identifies when a custom provider truly makes sense.
Quick Decision Tree
Do you need to manage infrastructure?
├─ NO → Use Terraform for orchestration only
│ Consider: shell scripts, Ansible, etc.
└─ YES
└─ Is there an existing provider?
├─ YES → Use or contribute to existing provider
└─ NO
└─ Can you use alternatives?
├─ YES → Explore: modules, null_resource, external
└─ NO
└─ Is this for production use?
├─ YES → Build custom provider
│ (follows this tutorial)
└─ NO → Prototype with alternatives first
When to Build a Provider: Strong Cases
✅ Case 1: Managing a New Platform
Scenario: You have infrastructure or services with an API that needs Terraform management.
Example:
- Internal cloud platform
- Custom Kubernetes operators
- Proprietary hardware management
- SaaS platform without Terraform support
Why a provider?
- Proper state management
- Native Terraform workflows
- Type safety and validation
- Dependency management
Example:
# Your internal platform
resource "myplatform_environment" "prod" {
name = "production"
region = "us-east"
replicas = 3
}
✅ Case 2: Heavy API Integration
Scenario: Complex API with many resources and relationships.
Characteristics:
- 10+ resource types
- Complex dependencies
- State must be tracked
- Frequent operations
Why a provider?
- Proper CRUD lifecycle
- State drift detection
- Import existing resources
- Plan/apply workflow
Anti-pattern (don’t do this):
# ❌ Bad: Using null_resource for complex API calls
resource "null_resource" "create_environment" {
provisioner "local-exec" {
command = "curl -X POST https://api.example.com/environments -d '{...}'"
}
}
# No state tracking, no updates, no deletes!
✅ Case 3: Team Standardization
Scenario: Multiple teams need consistent interface to platform.
Benefits:
- ✅ Enforces best practices
- ✅ Centralized logic
- ✅ Version-controlled configurations
- ✅ Self-service infrastructure
Example:
# Standard interface across teams
module "application" {
source = "./modules/standard-app"
name = "my-service"
# Provider handles complexity internally
}
✅ Case 4: Enterprise Requirements
Scenario: Enterprise needs governance, compliance, and auditability.
Requirements:
- Audit trails
- Role-based access control
- Compliance validation
- Approval workflows
Why a provider?
- Integrates with Terraform Cloud/Enterprise
- Policy-as-code support
- Sentinel integration
- Audit logging built-in
✅ Case 5: Existing Terraform Workflows
Scenario: Organization already uses Terraform extensively.
Benefits:
- Consistent tooling
- Existing CI/CD pipelines
- Team familiarity
- Unified state management
When NOT to Build a Provider
❌ Anti-Case 1: Simple Scripts
Scenario: One-time setup or simple configuration.
Use instead:
- Shell scripts
- Ansible playbooks
- Cloud-init
- Configuration management tools
Example:
# ❌ Don't need a provider for this
./setup-server.sh --config prod.yaml
❌ Anti-Case 2: No State Required
Scenario: Operations don’t need state tracking.
Use instead:
null_resourcewithlocal-exec- External provisioners
- Separate automation
Example:
# ✅ Good use of null_resource (stateless operation)
resource "null_resource" "notify_slack" {
provisioner "local-exec" {
command = "curl -X POST ${var.slack_webhook} -d 'Deployment complete'"
}
triggers = {
deployment_id = aws_instance.web.id
}
}
❌ Anti-Case 3: Existing Provider Available
Scenario: Provider already exists for your platform.
Action:
- Check Terraform Registry
- Evaluate existing provider
- Contribute improvements instead
Search:
# Check registry
terraform init
terraform providers
❌ Anti-Case 4: Rapid Prototyping
Scenario: Exploring concepts, not building production.
Use instead:
- Modules
- External data sources
terraform_dataresource
Example:
# ✅ Good for prototyping
data "external" "api_call" {
program = ["python", "${path.module}/call_api.py"]
query = {
endpoint = var.endpoint
}
}
❌ Anti-Case 5: Non-Infrastructure Resources
Scenario: Managing things Terraform wasn’t designed for.
Examples:
- Application configuration (use config management)
- User onboarding (use identity management)
- Data processing (use workflow engines)
Alternatives to Custom Providers
Alternative 1: Modules
Best for: Reusable infrastructure patterns
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "my-vpc"
cidr = "10.0.0.0/16"
}
Pros:
- No coding required
- Easy to share
- Version controlled
Cons:
- Limited to existing providers
- No custom state logic
Alternative 2: null_resource
Best for: One-off operations, triggers
resource "null_resource" "example" {
triggers = {
cluster_id = aws_eks_cluster.main.id
}
provisioner "local-exec" {
command = "kubectl apply -f manifests/"
}
}
Pros:
- Quick to implement
- No provider needed
Cons:
- Poor state management
- Limited functionality
- Hard to test
Alternative 3: External Data Source
Best for: Reading external data
data "external" "vault_secret" {
program = ["./scripts/get-secret.sh"]
query = {
secret_path = "secret/data/db"
}
}
output "password" {
value = data.external.vault_secret.result["password"]
sensitive = true
}
Pros:
- Flexible
- Any language
Cons:
- Read-only
- No state management
- No plan output
Alternative 4: External Provider
Best for: Generic command execution
resource "external" "api_call" {
program = ["node", "api-client.js"]
query = {
action = "create"
resource = "environment"
name = "production"
}
}
Pros:
- Quick prototypes
- Any language
Cons:
- Fragile
- Poor error handling
- Hard to maintain
Alternative 5: terraform_data
Best for: Lifecycle management without external resources
resource "terraform_data" "example" {
input = timestamp()
triggers_replace = {
version = var.app_version
}
}
Pros:
- Built-in
- Simple lifecycle
- No external dependencies
Cons:
- Limited functionality
- No API interaction
Cost-Benefit Analysis
Development Costs
Time investment:
- Initial development: 2-8 weeks
- Testing and debugging: 1-2 weeks
- Documentation: 1 week
- Ongoing maintenance: 2-4 hours/week
Expertise required:
- Go programming
- Terraform internals
- API integration
- Testing practices
Infrastructure:
- CI/CD pipelines
- Test environments
- Documentation hosting
Maintenance Costs
Ongoing:
- API changes
- Terraform upgrades
- Bug fixes
- Feature requests
- Security patches
Annual estimate: 20-40 hours/year minimum
Benefits
Quantifiable:
- Reduced deployment time
- Fewer manual errors
- Standardized workflows
- Self-service enablement
Qualitative:
- Better developer experience
- Improved reliability
- Infrastructure as code benefits
- Team scalability
Decision Matrix
Use this matrix to score your use case (1-5 scale):
| Criteria | Score | Weight |
|---|---|---|
| Number of resources (1=few, 5=many) | ___ | 3x |
| Complexity of operations (1=simple, 5=complex) | ___ | 2x |
| Frequency of use (1=rare, 5=daily) | ___ | 3x |
| Team size (1=individual, 5=large org) | ___ | 2x |
| Existing provider available (1=yes, 5=no) | ___ | 4x |
| State management needed (1=no, 5=critical) | ___ | 3x |
| Budget available (1=limited, 5=ample) | ___ | 2x |
Calculation:
Total = (Score × Weight) summed across all criteria
Maximum possible = 95
If Total > 60: Strong case for custom provider
If Total 40-60: Consider alternatives first
If Total < 40: Use alternatives
Common Use Cases
✅ Good Use Cases
- Internal cloud platforms
- Custom Kubernetes operators
- Private cloud APIs
- Self-service portals
- SaaS management
- Application configuration
- User provisioning
- Feature flags
- Hardware infrastructure
- Network devices
- Storage arrays
- Custom hardware
- Legacy systems
- Mainframe resources
- Proprietary databases
- Custom applications
- Compliance and governance
- Policy enforcement
- Approval workflows
- Audit logging
❌ Poor Use Cases
- One-time migrations
- Simple API wrappers
- Prototype projects
- Personal projects (unless learning)
- Non-infrastructure resources
When to Contribute vs Build
Contribute to Existing Provider If:
- ✅ Provider exists but missing features
- ✅ Bug fixes needed
- ✅ Community would benefit
- ✅ Maintainer is responsive
Example:
# Found AWS provider missing a resource?
# Contribute instead of forking!
git clone https://github.com/hashicorp/terraform-provider-aws
Build New Provider If:
- ✅ Platform has no provider
- ✅ Existing provider abandoned
- ✅ Fundamentally different approach needed
- ✅ Internal/proprietary platform
Testing the Waters
Before committing to full provider development:
Phase 1: Prototype (1 week)
# Test with external data source
data "external" "test" {
program = ["./scripts/api-call.sh"]
}
Validate:
- API reliability
- Error handling needs
- State requirements
Phase 2: Minimal Provider (2 weeks)
Build provider with:
- 1-2 resources
- Basic CRUD operations
- Minimal features
Validate:
- Development complexity
- Testing approach
- Maintenance burden
Phase 3: Decision Point
Expand if:
- Prototype successful
- Team adopting it
- Clear value demonstrated
Stop if:
- Too complex
- Low adoption
- Better alternatives found
Real-World Examples
Example 1: PagerDuty Provider
Decision: Build custom provider
Reasoning:
- ✅ Many resource types
- ✅ Complex dependencies
- ✅ Wide adoption
- ✅ State management critical
Result: Successful, 50K+ downloads/month
Example 2: Simple REST API
Decision: Use null_resource
Reasoning:
- ❌ Only 2 endpoints
- ❌ No state needed
- ❌ One-time setup
Result: Adequate solution
Example 3: Internal Platform
Decision: Build custom provider
Reasoning:
- ✅ 20+ resource types
- ✅ 100+ engineers using
- ✅ Daily operations
- ✅ Compliance required
Result: ROI positive within 6 months
Key Takeaways
- ✅ Build providers for complex, stateful infrastructure
- ✅ Consider alternatives for simple use cases
- ✅ Contribute to existing providers when possible
- ✅ Prototype before full commitment
- ✅ Calculate cost-benefit for your scenario
- ✅ Provider development is a long-term investment
- ✅ Maintenance is ongoing—plan for it
What’s Next?
Ready to build a provider? Let’s set up your development environment!
Previous: ← Provider Architecture & GRPC
Last updated: June 30, 2026