logo small e ntropitor

A Terraform Provider in TypeScript

Terraform is the leading Infrastructure as Code (IaC) tool. It allows you to manage your infrastructure in a declarative way. You define your desired state in configuration files and Terraform takes care of creating, updating, and deleting resources to match that state.

To be able to interact with different APIs and services, Terraform uses Terraform Providers. Providers are binaries that are started by Terraform and which expose a gRPC API to Terraform. Providers are responsible for understanding the API of the service they are managing and for translating the declarative configuration into API calls.

Because the gRPC API is quite barebones, HashiCorp, the company behind Terraform has created SDKs to help you write providers in Go. The plugin framework is their latest iteration on it after Terraform Plugin SDK v1 and v2. So far, they have only released SDKs for Go, but because gRPC servers can be created in almost any language, it is possible to write providers in other languages as well. Only, it's not super well documented and not encouraged at all by HashiCorp.

That didn't stop me from writing a provider in TypeScript though.

Why?

I wanted to learn more about how Terraform works under the hood. So I started reading and stumbled on the barebones gRPC API. I was intrigued and thus I started building a provider in TypeScript to see if it was possible.

TypeScript is a language which has a very strong type system. Many people underestimate it but if you use it right, it can give strong typing guarantees while allowing a lot of dynamism. Which makes it an ideal target for writing Terraform providers.

As an example, the ATproto records have the concept of a format for string-typed attributes like e.g. an URI. This is type-safe in TypeScript, you cannot assign a non-URI string to such an attribute. But you can assign an URI string to a string-typed attribute. In Go, you would have to use custom types and type assertions to achieve the same. Because the underlying ATproto SDK was typed well, it forced me to also type the provider schema well.

How?

I've build my own TypeScript SDK for building Terraform Providers. With it, I've built the ATproto Terraform Provider and published it to the terraform registry.

This involved a lot of reverse engineering and trial and error. The documentation is quite sparse and there are no examples of providers written in other languages than Go. The tutorial for writing a provider in Go helped to split the project in milestones and provided a mock service ("HashiCups", a fake coffee shop API) to test against. But given the tutorial is written to help you write a provider using the Go SDK, I still had to map everything to the gRPC API and figure out some details like the Terraform typesystem and how to encode that over messagepack.

As a user, you don't know in which language the provider is written in. However, I am super proud to have written the first provider in another language than Go. I really like to manage everything as code, and the fact that you can do it in your own language is a game changer. Hopefully, even more providers will be written so that providers are available even for smaller use cases.

Want to learn yourself?

Because I learned so much along this journey, I decided to create a course about it. In this course, you'll learn how to build a Terraform provider from scratch in your favorite programming language. But most importantly, you will learn how Terraform works under the hood and how you can build your own extensible software.

Do you want to learn more about how Terraform works under the hood?

Then check out my course.