Terralist is a self-hosted Terraform registry that speaks the official protocol
Terraform Private Registry for modules and providers manageable from a REST API
At a glance
- What is it?
- Terralist is a Go server that implements the Terraform registry protocols so your organisation can publish modules and providers to a private registry with a web dashboard, RBAC and pluggable storage. It suits platform teams that need a hosted Terraform registry, and it needs a real identity provider to be useful.
- Who is it for?
- Terralist is worth deploying when your organisation needs to publish Terraform or OpenTofu modules and providers to people outside a public registry, because it implements the registry protocols rather than asking anyone to change how they declare a source, and because the RBAC and API key model gives CI pipelines scoped credentials instead of a shared token.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Implementing the protocol is the whole point, and it is why Terraform needs no changes
The design decision is the first line of the description. Terralist implements the Terraform registry protocols and gives you a private, self-hosted registry with a web dashboard, RBAC, and support for multiple storage backends. That protocol compliance is what makes the tool usable, because the alternative to running your own registry is either publishing to the public registry or maintaining a fork of the client. The consumption side is shown in the usage examples, and the point is that nothing in the module block changes except the host name:
module "vpc" {
source = "registry.example.com/my-org/vpc/aws"
version = "1.0.0"
}The provider form is the same shape, with a `required_providers` entry carrying a `source` and a `version`. The source string encodes the registry host, the organisation, the namespace, the name and the provider system, so a team that points at `registry.example.com` gets modules and providers from the same place with the same credentials.
One binary, one config file, and three secrets you have to generate
The quick start is a download, a config and a start command. The release archive is fetched with the operating system and architecture interpolated from the Go environment:
curl -sL "https://github.com/terralist/terralist/releases/latest/download/terralist_$(go env GOOS)_$(go env GOARCH).zip" -o terralist.zip
unzip terralist.zipThe config is YAML, and the secrets in it are generated rather than chosen, which is the detail worth copying:
cat > config.yaml <<EOF
oauth-provider: github
gh-client-id: ${GITHUB_OAUTH_CLIENT_ID}
gh-client-secret: ${GITHUB_OAUTH_CLIENT_SECRET}
token-signing-secret: $(openssl rand -hex 16)
oauth-state-secret: $(openssl rand -hex 16)
cookie-secret: $(openssl rand -hex 16)
EOFThree separate secrets, one for signing tokens, one for the OAuth state parameter and one for cookies, each an independent 16-byte random value. The server then starts with `./terralist server --config config.yaml` and the dashboard is at `http://localhost:5758`. The features list calls out the single binary with no external dependencies that runs anywhere Go compiles to, and the getting started guide covers the HTTPS configuration that the Terraform CLI integration needs, which is the part the quick start leaves out.
RBAC is Casbin with three built-in roles, and API keys carry their own policies
Access control has two layers and they solve different problems. The first is role based, with fine-grained access control using built-in roles named `admin`, `readonly` and `anonymous`, and custom policies through Casbin. The second is the API key model, described as API keys with scoped policies, where you create keys for CI/CD with per-key RBAC policies and organizational scopes. The difference between them matters in practice. A person logging into the dashboard is a session with a role, and the role can be narrowed by a custom policy when the defaults are wrong. A pipeline is a credential that outlives a session, and scoping it to an organisation means a key leaked from one team cannot read another team's modules. The Go module pins `github.com/casbin/casbin/v2` at 2.135.0 and `github.com/casbin/govaluate` at 1.10.0, so the policy engine is a first-class dependency rather than a hand-rolled permission check, and the web dashboard's stated job includes managing authorities and API keys.
OAuth covers the usual providers and SAML covers the enterprise ones
Authentication is delegated to an identity provider, which is the reason the quick start config has GitHub client credentials in it. The features list names multiple OAuth providers, with GitHub, GitLab, BitBucket, or any OIDC-compatible provider, so a team on a corporate OIDC setup is not forced into a hosted service. The Go dependencies show the wider picture. `github.com/golang-jwt/jwt/v5` at 5.3.1 handles the token signing, and `github.com/crewjam/saml` at 0.5.1 is present, so SAML is on the table for organisations whose identity provider is not OIDC capable. The important consequence is architectural rather than cosmetic. Terralist does not hold user passwords, so a compromise of the registry is not a compromise of your identities, and a person can be added or removed in your identity provider and lose access here without anyone editing a user table.
Five storage backends, and the choice is fixed at configuration time
Artifacts can be stored in AWS S3, Azure Blob, Google Cloud Storage, the local filesystem, or a proxy mode. The Go module shows the implementation weight behind that list, with the AWS SDK v2 at 1.47.3 including the S3 service and the credentials and config packages, the Azure SDK for Go with azcore, azidentity and the azblob storage package, the Google Cloud Storage client, and `modernc.org/sqlite` at 1.53.0 for a SQLite-backed local option. The local filesystem backend is what makes a single-node install with no cloud account possible, and the proxy mode is for organizations that already have an artifact store and want Terralist to sit in front of it. The consequence of the list is that Terralist is not storage-agnostic at runtime, the backend is a deployment decision, and the Cloud Storage and S3 clients are compiled into the binary whether you use them or not. The database side is separate from the artifact side, with GORM at 1.31.2 and drivers for MySQL, Postgres and SQLite, so the metadata can live in a relational database while the archives live in object storage.
Prometheus metrics and a web dashboard in the same product
Two observability surfaces are included, and they answer different questions. The Prometheus metrics cover uploads, downloads, API key usage, storage operations, and HTTP request latency, which is what a platform team puts in a scrape config and then alerts on. The web dashboard is for a person, and its described jobs are browsing artifacts, viewing documentation, and managing authorities and API keys. The module pins `github.com/prometheus/client_golang` at 1.24.1, so the metrics are exposed in the standard format rather than something custom. The web frontend is a separate part of the build, and the Dockerfile shows it, with a Node 24 Alpine stage that installs the web dependencies with yarn using a frozen lockfile and runs a yarn build, whose output is then copied into the Go build stage. The Go binary then serves the built frontend from the same process, which is why the release can be a single file with no external dependencies.
The build and the release pipeline are both in the repository
The repository contains the full development apparatus, and the shape of it tells you what kind of project this is. The root holds a `Taskfile.yaml` for task running, a `Dockerfile` and a separate `Dockerfile.test`, a `.golangci.yml` for linting, a `.mockery.yml` for mock generation, a `.goreleaser.yml` for the release artifacts, and a `.mise.toml` for tool versions, with a `.go-version` file pinning the Go release. There is a `cmd/` directory for the command tree, `internal/` for the implementation, `pkg/` for the public packages, `e2e/` for end-to-end tests, `docs/` and an `mkdocs.yml` for the documentation site, and a `web/` directory for the frontend. The go.mod file declares Go 1.26.4. The Dockerfile is a three-stage build that ends in a plain alpine image, creates a `terralist` group and user, and stamps the binary with the version, commit hash, build timestamp and mode through linker flags, so a running container can report exactly which build it is.
Where a private registry is the wrong answer
Two limits are worth naming. The first is that Terralist solves a problem you may not have. If your organisation consumes modules from a public registry and publishes a handful of internal ones, a private registry is a service to run, secure, back up and keep on a supported version, and the public registries already work. The second is the identity dependency. Every path into the product runs through an OAuth or SAML provider, so an organisation that cannot run one, or that wants its own user table, has to build around the edges of the product rather than use it as intended. The alternative to weigh against is a hosted private registry with the same protocol, which removes the operation and keeps the protocol compatibility, and the difference in approach is ownership. Terralist gives you the registry and the policy engine and the dashboard, and asks you to run them. A hosted service gives you the protocol and asks for a monthly fee and a data residency decision. The second is the smaller commitment for most teams, and the first is the right answer when the modules are sensitive enough that they must not leave your network, or when the API key scoping and the organisational boundaries are worth owning.
Editorial conclusion
Terralist is worth deploying when your organisation needs to publish Terraform or OpenTofu modules and providers to people outside a public registry, because it implements the registry protocols rather than asking anyone to change how they declare a source, and because the RBAC and API key model gives CI pipelines scoped credentials instead of a shared token. It is a poor fit for a team that only consumes modules, since the problem it solves does not exist for them, and a poor fit if you have no way to run an OAuth provider, because the quick start config assumes GitHub credentials. Before deploying it, decide which storage backend you want, since the choice is fixed at configuration time and includes S3, Azure Blob, Google Cloud Storage, the local filesystem and a proxy mode, and note that the last push to the repository was on 2026-10-20 with release v0.11.0 published on 2026-09-29.
Frequently asked questions
What is Terralist and what does it implement?
Terralist is a Go server that implements the Terraform registry protocols and gives you a private, self-hosted registry with a web dashboard, RBAC and multiple storage backends. Modules and providers are consumed with a normal source string pointing at your own host, so no client changes are needed.
How do I install and start Terralist?
Download the release zip with curl, unzip it, write a config.yaml with an oauth-provider and its client id and secret plus three generated secrets for token signing, OAuth state and cookies, then start it with ./terralist server --config config.yaml and open http://localhost:5758. The getting started guide covers the HTTPS configuration the Terraform CLI integration needs.
How does Terralist handle access control and API keys?
RBAC is provided with built-in roles named admin, readonly and anonymous, and custom policies through Casbin. On top of that, API keys for CI/CD can be created with per-key RBAC policies and organizational scopes, so a credential can be limited to one organisation.
Where can Terralist store artifacts?
The documented storage backends are AWS S3, Azure Blob, Google Cloud Storage, the local filesystem, and a proxy mode. The backend is a configuration-time decision, and the Go dependencies include the AWS SDK v2, the Azure SDK for Go and the Google Cloud Storage client alongside a SQLite driver for the metadata database.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/terralist-terralist)Was this useful?