Orchestrion rewrites your Go code at compile time to add tracing
Automatic compile-time instrumentation of Go code
At a glance
- What is it?
- Orchestrion is a compile-time instrumentation tool for Go that rewrites source code during the build, with the integrations you want selected by imports in an orchestrion.tool.go file. It is vendor agnostic, Apache-2.0 licensed, and works through Go modules only.
- Who is it for?
- Orchestrion fits Go teams that want APM traces across a service without touching every call site, and that want the instrumentation set chosen in one file rather than scattered through the code. It is the wrong tool if your project is not on Go modules, if you are pinned to a Go release outside the two newest, or if you need traces that only an OpenTelemetry integration can provide and no such integration exists for your libraries yet.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The imports in orchestrion.tool.go are the configuration
Orchestrion processes Go source code at compilation time and inserts instrumentation into it. What gets instrumented is decided by a single file, the orchestrion.tool.go file at the project root, and it is decided by what that file imports.
Importing the tracer's root module, github.com/DataDog/dd-trace-go/v2, in that file enables automatic instrumentation of all supported integrations, and the list of those integrations lives on the documentation site rather than in the repository. If you want a smaller set, you can cherry-pick by importing the package paths of the specific integrations you want instead of the tracer's root module.
That is an unusual and rather good design decision. Instead of a configuration file, a build tag or a runtime environment variable that lists package names, the selection mechanism is ordinary Go import statements in a file that the Go toolchain already understands. The file compiles, so a typo is caught by the compiler, and the selection is visible in the same place as the module requirements that make the instrumentation possible.
The repository carries a working example of this file, at samples/orchestrion.tool.go, next to a samples directory with client, server and crashtracker subdirectories and a regression test.
Compile-time rewriting instead of a runtime agent
The mechanism that distinguishes Orchestrion from a runtime tracing agent is that the instrumentation exists in the binary as compiled code rather than being attached to a running process.
That has consequences in both directions. On the positive side, there is no sidecar process to deploy and no runtime configuration to keep in sync, and the instrumentation is subject to the same compiler checks as the rest of your code, so a mismatched signature is a build failure rather than a surprise at startup. On the negative side, the rewrite happens to your source, which means the build output is not byte-for-byte what you wrote, and the inserted code has to be understood when something goes wrong.
The project treats that second point as a first-class concern rather than an inconvenience. The contributor guide is described as providing more detailed information about how orchestrion works and how to contribute new instrumentation, which tells you that the rewrite is something you are expected to understand if you extend it.
The alternative approach, and the one most teams start with, is manual instrumentation: import the tracer in the code that needs it and wrap the calls or decorate the handlers yourself. The difference in approach is ownership. Manual instrumentation leaves your call sites readable and explicit but requires an edit per call site and drifts as the code changes, while compile-time rewriting keeps the call sites untouched and moves the coupling into the build.
Go modules and the two newest Go releases are hard requirements
Two constraints decide whether you can use Orchestrion at all, and both are stated plainly in the readme.
The first is Go modules. Orchestrion only supports projects using Go modules. There is no fallback for a project in GOPATH mode, and no mention of one.
The second is the Go version. Orchestrion supports the two latest releases of Go, matching Go's official release policy. The readme adds a careful qualification: it may function correctly with older Go releases, but the project will not be able to offer support for those if they fail.
That distinction between working and being supported is the one to hold on to. An older toolchain is not a hard error, but a bug report against it is a bug report the maintainers have said they cannot service, and the module file itself declares go 1.26.0, so the repository is built against a recent release.
The go.mod also shows what a dependency this size looks like. Alongside the tracer at v2.11.2, the direct requirements include a Go AST library for source manipulation, a code generation library, the Go language server tooling packages, a CLI framework and a test assertion library.
module github.com/DataDog/orchestrion
go 1.26.0
require (
github.com/DataDog/dd-trace-go/v2 v2.11.2
)orchestrion pin sets the file up, and you can narrow it afterwards
The command that appears in the readme is orchestrion pin, and the tip attached to it explains the default behaviour. By default, orchestrion pin enables Datadog's tracer integrations by importing github.com/DataDog/dd-trace-go/v2 in orchestrion.tool.go.
That default is the starting point, not the answer. The readme is explicit that Orchestrion is a vendor-agnostic tool, and that other vendors, OpenTelemetry among them, may provide alternate integrations that can be used instead. The same tip that documents the Datadog default is the one that tells you it is not the only option.
So the intended workflow has two stages. You pin to get a valid orchestrion.tool.go file with a working import, you build and see what the tracer produces, and then you narrow the selection by replacing the root import with the specific integration package paths you actually want. The result is a file whose contents are small enough to read in a code review.
The documentation split follows that workflow. The user guide covers available configuration and how to customize the traces produced by your application, while the contributor guide covers how the tool works and how to add instrumentation to it. Getting started is pointed at a section of the Datadog user guide rather than at a page in this repository, which is a sign that the documentation lives outside the repo.
A build with the -work flag shows you every rewritten file
The troubleshooting section in the readme is the most practically useful part of the document, and it is short.
The first technique is the -work argument on the go build command. When it is present, the build emits a WORK= line pointing at a working directory, and that directory is retained after the build finishes. Its contents include all the updated source code Orchestrion produced, along with additional metadata, which is exactly what you need to see what the tool did to your code.
The second is what to put in a bug report. The readme asks for the version of orchestrion, obtained from orchestrion version, and the version of the Go toolchain, from go version. Both are described as essential and required with any bug report.
The support model is layered. Bugs go to the GitHub issue tracker, general questions to GitHub discussions, and private contact through Datadog support. Since the tool is built by the vendor of one of the tracing backends, that split makes sense: the community channels are where the mechanics belong, and the private channel is where anything about your production environment belongs.
If you are evaluating the tool, running one build with -work before you commit to it is the cheapest way to see whether the rewrite is doing what you expect.
Building the tool from the Makefile
If you want the binary rather than a pinned version, the repository builds it with make. The default goal is help, and the two targets that matter are build and install.
build: ## Build orchestrion binary to bin/orchestrion
go build -o bin/orchestrion main.goinstall: ## Install orchestrion to $$GOPATH/bin
go install .The broader target set shows the project's own quality gates. The all target chains build, format, lint and test. Formatting is split across Go, YAML and shell, with golangci-lint for Go, yamlfmt for YAML and shfmt for tracked shell scripts and Bats tests. Linting has separate targets for GitHub Actions workflows, Makefiles and shell, and there are dedicated test targets for Bats tests and for end to end runs.
The repository root also shows the shape of the project itself: an instrument/ directory, an internal/ directory, runtime/, samples/, test/, a main.go at the root, and a linkorder_test.go alongside a noimports_test.go, which are the kinds of tests you write when the tool's contract is about how it links and what it imports.
Licensing is Apache-2.0, with a LICENSE file at the root, a NOTICE file and a LICENSE-3rdparty.csv that records the third party licences the project carries.
Where compile-time instrumentation is the wrong choice
The clearest case against Orchestrion is a project that is not on Go modules, or a team pinned to a Go release outside the two newest. There is no workaround for either in the documentation.
The second case is coverage. The set of integrations that can be enabled is bounded by what the integrations exist for, and the list lives on the documentation site rather than in the repository. If your service uses a framework or a library that no integration covers, no amount of pinning changes that, and you will have found yourself writing manual instrumentation anyway for that part of the codebase.
The third case is the coupling. Because the selection of instrumentation is expressed as imports in a file, the effect of adding an integration is not local to a package. It changes what the build injects across the module, and it changes what the traces contain. A service that wants very specific spans may find the automatic set either too broad or shaped differently than the team expects, and the readme is candid that customising the traces your application produces is a documented task rather than an automatic result.
For those reasons, the sensible adoption pattern is incremental: pin, build with -work, read the rewritten output, narrow the imports to what you want, and keep manual instrumentation for the cases no integration covers.
Editorial conclusion
Orchestrion fits Go teams that want APM traces across a service without touching every call site, and that want the instrumentation set chosen in one file rather than scattered through the code. It is the wrong tool if your project is not on Go modules, if you are pinned to a Go release outside the two newest, or if you need traces that only an OpenTelemetry integration can provide and no such integration exists for your libraries yet. Check first that the integrations you need exist for your framework, that the orchestrion.tool.go file at your project root is the one the build actually reads, and that a build with the -work flag shows you the rewritten source before you ship it.
Frequently asked questions
How do I enable instrumentation with Orchestrion?
Import github.com/DataDog/dd-trace-go/v2 in the orchestrion.tool.go file at the project root, which enables all supported integrations. Importing the package paths of specific integrations instead lets you cherry-pick which ones are enabled.
Which Go versions and setups does Orchestrion support?
It supports the two latest Go releases, matching Go's official release policy, and only projects using Go modules. It may work with older Go releases, but those are not supported if they fail.
Is Orchestrion tied to Datadog?
No. The project states that Orchestrion is vendor-agnostic. While orchestrion pin enables Datadog's tracer integrations by default, other vendors such as OpenTelemetry may provide alternate integrations that can be used instead.
How can I see what Orchestrion changed in my build?
Add the -work argument to your go build command. The build then emits a WORK= line pointing at a working directory that is kept after the build and that contains the updated source code Orchestrion produced.
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/datadog-orchestrion)Was this useful?