terraform-ls is the official Terraform language server, and it publishes what it cannot yet do
Terraform Language Server
At a glance
- What is it?
- terraform-ls is the Terraform language server maintained by HashiCorp, written in Go under the MPL-2.0 and built on HashiCorp's own HCL libraries, so it can offer any LSP compatible editor completion, validation and navigation over Terraform configuration. The README is unusually candid that not all language features are available yet, and the project asks for bug reports on its pre-releases.
- Who is it for?
- terraform-ls suits a team editing Terraform in an editor that supports the language server protocol, who want the official implementation rather than a community one, and who accept that some features are still missing and that the provider schema is only as fresh as the Terraform binary it can find.
- 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 2 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The feature matrix is the honest part of the README
terraform-ls is described as the official Terraform language server maintained by HashiCorp, providing IDE features to any LSP compatible editor. That first line is the positioning, and it is not a claim many third party projects can make.
The second line is the one to read carefully. Not all language features, from LSP's perspective or any other, are available at the time of writing, but the project describes itself as active with the aim of delivering smaller, incremental updates over time. And it points at a document, the LSP feature matrix in docs/features.md, which lists what works and what does not.
That combination is what makes the project usable. A language server that silently omits a capability is much worse than one that says so, because a developer will assume the editor is broken rather than the feature missing. Publishing a matrix means you can check whether the thing you need, hover documentation, completion, validation, go to definition, is implemented before you commit to a setup, and file an issue against a specific row if it is not.
The audience is therefore Terraform users on editors that speak LSP, which by now covers most of the field, and the second audience is the developers who want to understand why a feature is missing and file a good issue. The README asks people to browse existing issues and open a new one if they hit a bug or have an idea for a feature.
The implementation is HashiCorp's own HCL stack
The dependency list is the clearest description of how the server works, and it is unusual for a language server to depend on the tool it serves.
The core is github.com/hashicorp/hcl-lang, the language implementation library, alongside hcl/v2 for parsing the configuration language itself. On top of that sit terraform-schema, which is the schema of the providers and resources, terraform-json for the JSON output format of Terraform, terraform-registry-address for parsing provider and module addresses, and terraform-exec, which is a wrapper around running the Terraform binary. That last one is the significant entry: some of what the language server can offer, such as knowing what a module will output or what the current state of a resource is, requires asking Terraform itself rather than reading files.
The rest of the list is the infrastructure of a language server. creachadair/jrpc2 is a JSON-RPC 2.0 implementation, which is the transport LSP runs over. hashicorp/go-memdb is an in-memory database, and the go-memdb dependency is what backs the server's index of the workspace, so that a query across hundreds of files does not mean re-parsing all of them. hc-install is the library HashiCorp uses to find or download a Terraform binary, which is how the server locates the CLI it needs. zclconf/go-cty carries the value types, golang.org/x/tools supplies the language analysis, and go.opentelemetry.io/otel/trace shows that the server is instrumented for tracing.
The consequence for a user is that the server's knowledge has two layers, and they age differently. The first layer comes from the HCL parser and the provider schema, and it is as fresh as the schema data the server has. The second comes from running Terraform, and it is only as fresh as the binary that is installed.
Installation is usually the editor's job
The installation section is short because in most cases it is not your job. Some editors have built-in logic to install and update the language server automatically, so you may not need to worry about installation or updating of the server. The rest of the section points at the installation page in docs/installation.md.
That design decision is sensible for a server that most people meet through an editor plugin rather than directly. The same applies to usage. The most reasonable way you will interact with the language server is through a client represented by an IDE, or a plugin of an IDE, and the README points at the relevant guide for your IDE in docs/USAGE.md. Per IDE guides, rather than one README, is the right shape for a project whose users arrive through a dozen different clients.
The one part of installation that does need attention is the Terraform binary. The dependency on terraform-exec and on hc-install means the server wants a Terraform CLI available, either one it finds on the path or one it installs. That matters for two reasons. The first is that the version of Terraform on your machine determines how much the server can tell you, because the provider schema and the language behaviour both move with the CLI version. The second is that some capabilities may invoke the Terraform binary against your real configuration and credentials, and that is a decision about your environment rather than about your editor.
For a reader who wants the exact commands, the installation page is the place to look, because the answer differs by editor and by how the client starts the server.
Pre-releases are the feedback channel, and they ask for bug reports
The stability section is short and unusually operational.
The project aims to communicate its intentions regarding breaking changes via semver, and it may use pre-releases with a version shape like MAJOR.MINOR.PATCH-beta1 to gather early feedback on certain features and changes. The release history shows the pattern in practice, with v0.38.8, then a v0.39.0-beta5, then v0.39.0.
Two things follow from that. The first is that a version number alone does not tell you the maturity of a feature, because a beta can sit inside a minor version that later ships as stable, and the feature matrix is the document that says which is which. The second is what the project asks of users: report any bugs in any versions, but especially in pre-releases, if you decide to use them.
That request is the interesting part. A language server's failure mode is confusing, since an incomplete completion or a wrong diagnostic looks like an editor problem rather than a server problem, and pre-release users are the only people who will find those failures before the release does. The project's position, that a pre-release is where the feedback happens, is a candid way of describing who is doing the testing.
A team that adopts pre-releases should therefore expect to file issues and to be part of the release process for the features they need. A team that just wants a working editor should stay on the stable tags and read the feature matrix.
Telemetry is opt-in and has to be requested by the client
The telemetry section is two sentences and they matter more than they look.
The server will collect data only if the client requests it during initialization, and telemetry is opt-in by default. The detail to hold on to is who decides. It is the editor client, not the server, that has to ask, so the switch lives in the configuration of the editor plugin or the LSP client, and a user who has never touched that setting is not sending anything.
That is a well constructed arrangement. Language servers run continuously inside an editor, often across a whole workspace, and a server that phoned home by default would be a problem for every corporate environment. Making the client the initiator means the data flow is a property of the tool the user already configured, and a user who wants nothing has to do nothing.
The documentation is at docs/telemetry.md for the details of what is collected when it is enabled.
For a team, the practical question is not whether telemetry is on by default, since the README is clear that it is not, but whether your editor's client requests it and whether the person who configured the editor knew. That is a question about your own configuration, and it is worth answering before the server is rolled out to a team rather than one developer.
The release machinery is in the repository, not in a wiki
The top level of the repository is a good indicator of how the project is run.
There is a.changes/ directory and a.changie.yaml, and Changie is the changelog tool that collects structured change entries and renders them into CHANGELOG.md. That combination means the changelog is generated from entries rather than written by hand, which is why the history is consistent and why contributors have a mechanical way to describe their change rather than needing to edit prose.
Then there is.copywrite.hcl, which is the configuration for HashiCorp's copywrite tool, used to add and check copyright headers across the source. And there is.go-version, which pins the Go toolchain, matching the go directive in go.mod.
The rest of the tree is the code and the plumbing: main.go and version.go and the version/ directory for the build metadata, internal/ for the implementation, tools/ and tools.go for the tool dependencies, and a.release/ directory for release configuration. algolia.go at the root is a small but telling file, since it points at the Algolia client that powers the search on the documentation site, which is listed among the module's dependencies in go.mod.
The dependency list shows the test tooling as well. google/go-cmp for comparisons, stretchr/testify for assertions, vektra/mockery for mock generation, and go.bobheadxi.dev/gobenchdata, which is a benchmark data set, suggesting the project cares about the performance of parsing and indexing rather than only about correctness.
What the language server cannot do, and what to use instead
There are three honest limits, and they are worth stating before anyone adopts this.
The first is the feature matrix itself. The README says plainly that not all language features are available. Whatever is missing is missing, and no configuration change brings it back, so the check is the matrix.
The second is the dependency on a Terraform binary. Because the server can run Terraform to obtain information that cannot be read from files, its answers are only as good as the CLI it finds, and in an environment where the CLI is not installed, or is a different major version, or is not allowed to run, the server degrades. A team that forbids running Terraform from the editor, for instance because of credential handling, will get a reduced feature set, and the README does not enumerate which features those are.
The third is the overlap with the editor. Several editors ship their own Terraform support, and some editors install and update the language server for you. Where an editor's built-in integration is adequate, adding terraform-ls on top means two systems answering the same questions, and the practical benefit is in the specific capabilities the matrix lists and your editor lacks.
The alternative worth naming is the community implementation that the README credits, terraform-lsp by Julio Sueiras. The difference in approach is that terraform-ls is built on the vendor's own HCL libraries, which means its parsing and schema behaviour track the official tool rather than approximating it. For a team that has to trust the diagnostics, that is the deciding factor, and it is also why the gap in feature coverage matters more here than it would for a third party server.
Editorial conclusion
terraform-ls suits a team editing Terraform in an editor that supports the language server protocol, who want the official implementation rather than a community one, and who accept that some features are still missing and that the provider schema is only as fresh as the Terraform binary it can find. It does not suit a team that needs a specific editor feature today and cannot wait for a release, and it is the wrong tool if your policy forbids the language server to run the Terraform binary on your machine. Verify first that the LSP feature matrix covers the capabilities you actually rely on, that the version of Terraform the server can find matches the providers your configuration uses, and that your editor's client does not request telemetry you did not intend to send.
Frequently asked questions
What is terraform-ls and who maintains it?
It is the official Terraform language server maintained by HashiCorp, written in Go under the MPL-2.0, and it provides IDE features to any editor that speaks the Language Server Protocol.
Does terraform-ls support every LSP feature?
No. The README states that not all language features are available at the time of writing, and points at the LSP feature matrix in docs/features.md, which lists what is implemented and what is not.
How do I install terraform-ls?
Usually you do not need to. Some editors have built-in logic to install and update the language server automatically, and the README points at the installation page in docs/installation.md and at the per IDE usage guide in docs/USAGE.md for the rest.
Does terraform-ls send telemetry?
Only if the client requests it during initialization, and telemetry is opt-in by default. The decision therefore sits with the editor client configuration, and the details are in docs/telemetry.md.
Does terraform-ls need the Terraform CLI installed?
The dependency list includes terraform-exec and hc-install, the library HashiCorp uses to find or download a Terraform binary, so parts of the server's behaviour comes from running Terraform. The version of Terraform available therefore affects how much the server can tell you.
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/hashicorp-terraform-ls)Was this useful?