Our Terraform provider now covers 28 resource types across compute, networking, DNS, and load balancing. Here's what we learned about building a production-quality provider from scratch.
When we launched the Sigilhosting API in early 2024, several community members immediately started building unofficial Terraform providers. We appreciated the effort, but the providers had coverage gaps, inconsistent error handling, and no guaranteed maintenance. Rather than coordinating across multiple community efforts, we decided to build and maintain an official provider ourselves.
The decision came down to a core belief: infrastructure-as-code is not optional for serious users. If our Terraform provider is unreliable or incomplete, customers can't treat Sigilhosting the same way they treat AWS or GCP in their configurations. We'd always be the "manual step" in otherwise automated workflows — and that eventually drives customers to providers with better IaC support.
We built the provider using HashiCorp's terraform-plugin-framework (the newer SDK, not the legacy terraform-plugin-sdk). The framework's type system catches more bugs at compile time and makes it easier to implement complex nested attributes like load balancer routing rules and firewall policies.
// Sigilhosting VPS resource schema (simplified)
func (r *VPSResource) Schema(_ context.Context,
_ resource.SchemaRequest,
resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"region": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"plan": schema.StringAttribute{Required: true},
"image": schema.StringAttribute{Required: true},
"ssh_keys": schema.SetAttribute{
ElementType: types.StringType,
Optional: true,
},
},
}
}
We shipped with 6 resource types (VPS, SSH key, firewall, private network, floating IP, DNS zone) and expanded to 28 over 14 months. The hardest resources were load balancers (three complete rewrites of state flattening logic due to deep nesting) and Kubernetes clusters (asynchronous 3-5 minute provisioning required polling loops with exponential backoff).
| Category | Resources | Count |
|---|---|---|
| Compute | VPS, dedicated server, bare metal, GPU, snapshot, SSH key | 6 |
| Networking | Firewall, FW rule, private network, floating IP, reserved IP | 5 |
| Load Balancing | Load balancer, forwarding rule, backend pool, health check | 4 |
| DNS | Zone, record, DNSSEC | 3 |
| SSL | Certificate, Let's Encrypt cert | 2 |
| Kubernetes | Cluster, node pool, volume, secret | 4 |
| Other | Domain, project, API token, webhook | 4 |
Every resource has acceptance tests against the real Sigilhosting API. Each CI run creates a dedicated account, executes 342 tests covering create, read, update, delete, and import for each resource, then tears down. Full suite: ~45 minutes, ~$12 per run.
Every bug we've shipped in the Terraform provider was in a code path that wasn't covered by an acceptance test running against the real API. Mocks give false confidence.
Import functions are auto-generated from our OpenAPI specification. A code generator reads the API schema for each resource type and produces an importer that fetches and maps every field. When we add attributes, import functions update automatically in the next release.
Three priorities for 2026: Terraform CDK library (TypeScript, Python, Go instead of HCL), provider-level caching to reduce API calls from ~2,000 to ~400 per plan for 500-resource configs, and drift detection alerts for changes made outside Terraform. The provider is open source at github.com/sigilhosting/terraform-provider-sigilhosting.