September 30, 2026·4 min read·engineeringterraformmoduleslinting

OpenTofu 1.13 experiments with reusable symbols and linting

OpenTofu 1.13 previews symbol libraries and built-in linting. The experiments raise useful questions about sharing configuration logic and enforcing conventions across modules.

OpenTofu 1.13.0, released on September 30, introduces experiments for symbol libraries and built-in linting. Its release announcement describes symbol libraries as reusable collections of values, functions, and type aliases. Linting begins with early built-in checks, with a stated interest in eventually incorporating related needs such as policy enforcement. Both experiments concern how authors maintain configuration across more than one module.

I use Terraform's configuration model by default and value its ability to make API abstractions reusable. OpenTofu is particularly interesting to me because of its licensing. These experiments give me another reason to follow its language design. I want to know whether reusable expressions can have a clearer home, and whether configuration checks can explain a convention before an infrastructure operation reaches a remote API.

The experimental status is part of the announcement's substance. The release-tag changelog says symbol libraries are subject to change and should not be relied on in production. I would evaluate their design with small examples and give feedback on the interface. I would keep production module requirements tied to behavior the project has committed to supporting.

A library has a different responsibility from a module

The release describes a symbol library as an artifact that can be imported from the source types already supported for modules. Its contents are reusable language definitions. That suggests a way to share a function or type alias without making the consumer treat it as a module that manages infrastructure. The proposal is useful precisely because sharing an expression and managing a resource are different responsibilities.

For a trial, I would start with one repeated transformation and one type definition. I would compare the resulting caller configuration with the duplicated version and ask whether readers can still understand the value's origin. Reuse has a maintenance cost when an expression becomes hard to locate. A library needs to make that dependency understandable in ordinary configuration review.

I would also examine how a library change affects its consumers. A function can keep the same name while changing the value it returns for an existing input. A type alias can change which configurations are accepted. The fact that the artifact contains language definitions does not remove the need for compatibility discipline.

Those are evaluation questions, not claims that the experiment has settled each design choice. The changelog explicitly asks for feedback on the language design and its integration with OpenTofu workflows. I would use that opening to report cases where library boundaries help, and cases where they obscure the expression a module author needs to inspect.

An experiment also needs a realistic path for removal from a trial configuration. Before depending on it for a large collection of modules, I would keep the original expression available and establish how much caller configuration must change if the syntax changes. That bounds the cost of contributing useful feedback while the project still considers the design unsettled.

Linting begins as warning diagnostics

The changelog says supported commands accept a -lint flag to enable the new checks. OpenTofu runs selected lint rules against the configuration and reports issues as warning diagnostics. The project calls this an initial iteration and wants feedback on how people interact with it. That is a narrower statement than promising a complete policy system in this release.

I would distinguish a lint warning from an invalid configuration and from a prohibited infrastructure action. Each answers a different question. A convention can be useful even when violating it leaves configuration executable. A policy might need an enforcement decision with consequences beyond printing a warning. The release's interest in combining related needs does not make those behaviors equivalent today.

My first trial would use configurations with known convention violations and compare the diagnostics with what a reviewer would ask the author to change. I would check that a warning points to a useful location and explains the issue. I would also include acceptable configurations, because a check that repeatedly warns on intentional patterns can reduce the value of its output.

For automation, I would inspect the actual warning behavior before treating linting as a required gate. The changelog promises warning diagnostics, so I would not assume that a lint finding automatically gives the command a failing exit status. Any surrounding enforcement would need to be explicit and tested against the version being evaluated.

Stable upgrade changes still need attention

OpenTofu 1.13 adds official Windows ARM64 packages. The changelog cautions that providers may not support that platform even when OpenTofu itself does. I would verify the providers required by a configuration before treating the executable's availability as proof that the entire workflow can run on that machine.

I would include provider installation in that platform check and record which package was selected. A missing provider build is a distribution constraint that language experiments cannot address. It needs a separate decision about where the configuration will run.

The release also removes WinRM support for provisioners after deprecating it in 1.12. The changelog attributes this to unmaintained upstream libraries and suggests SSH as a migration direction. A configuration that still uses the removed connection type needs work independently of any decision about symbol libraries or linting.

Another compatibility note concerns base64gzip. Its results can differ byte for byte while decompressing to the same original bytes because the compression implementation changed. The changelog warns that providers may respond to the differing encoded value by planning an update or replacement. I would inspect those changes as part of an upgrade review even when the source text has not changed.

These stable changes shape how I would schedule an evaluation. First I would establish that the existing configuration works with the new executable and its compatibility changes. Then I would enable an experiment in a limited configuration with known expected results. That keeps feedback about library design or lint diagnostics specific to the behavior under examination and gives the project a reproducible example to assess.