# Bruin ships one Go binary that needs CGO, and its Makefile explains every pin

> Bruin is a data pipeline tool written in Go that runs SQL, Python and R transformations against warehouses, with table materializations, built-in quality checks, Jinja templating and dry-run validation. The build configuration is unusually self-documenting: pinned lint tool versions carry comments explaining why they cannot move.

**bruin-data/bruin** — Build data pipelines with SQL and Python, ingest data from different sources, add quality checks, and build end-to-end flows.

- Repository: https://github.com/bruin-data/bruin
- Website: https://getbruin.com/docs/bruin/
- Stars: 1,787 · Forks: 98
- Language: Go
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/bruin-data-bruin

## SQL, Python and R in one pipeline definition

Bruin is described as a data pipeline tool that brings data ingestion, data transformation with SQL, Python and R, and data quality into a single framework.

That combination is the positioning. Most tools in this category pick two. A warehouse-native orchestrator does SQL well and treats everything else as a foreign body. A Python-first tool does transformation well and pushes SQL logic into files. Bruin's claim is that all three languages coexist in one pipeline definition, which is what makes it usable for a team where the warehouse team writes SQL, the analytics team writes Python and a statistician writes R.

The feature list fills in the mechanics. Ingestion is handled through ingestr or through Python. Transformations run on many platforms. There are table and view materializations and incremental tables. Python runs in isolated environments managed by uv, which is the mechanism that lets a pipeline declare a dependency without you managing a virtualenv by hand.

Jinja templating is included for repetition, which is the standard answer to pipelines where the same three lines of column logic appear in forty queries.

Quality checks are built in rather than bolted on, and the examples directory contains a simple-pipeline case and an inference case, which suggests the authors expect people to try both shapes.

The tool is written in Go and the README states it runs on your local machine, an EC2 instance, or GitHub Actions, with secrets injected through environment variables. There is a VS Code extension for the editor experience, which is the difference between a tool people use in CI and one they use daily.

## The dependency list is a map of what Bruin can talk to

The go.mod is long and it is worth reading as a capability list rather than as noise.

Google is there with `cloud.google.com/go/bigquery`, `dataproc/v2`, `storage` and `longrunning`. AWS has the v2 SDK split properly across modules: `config`, `credentials`, `feature/s3/manager`, `service/emrserverless`, `service/quicksight`, `service/s3` and `service/secretsmanager`. Azure has `azcore`, `azidentity` and a Key Vault secrets package.

Data platforms include `databricks-sql-go`, `clickhouse-go/v2`, `pgx/v5`, `go-sql-driver/mysql` and `columnar-tech/dbc`. That last one plus `unixodbc` in the Docker image tells you generic ODBC connectivity is a supported path, which is how you reach the warehouse nobody has a native driver for.

Two entries explain local and file-based work. `apache/arrow-go/v18` and `apache/arrow-adbc/go/adbc` are Arrow implementations, and `machineid` from denisbrodbeck is used for machine identification.

The user-facing side shows the author cares about terminal experience: three charmbracelet libraries, bubbletea for the interactive loop, bubbles for widgets and lipgloss for styling. Two formatters, chroma for syntax highlighting and expr-lang for an expression evaluator, suggest the CLI renders coloured, formatted output rather than plain text.

There is also Vault and retryable HTTP in the dependency set, which is what a tool looks like when it expects to run inside a company's platform team rather than on a laptop.

Telemetry is a variable in the Makefile, set to `TELEMETRY_OPTOUT=1` with an empty telemetry key, so the local build path defaults to opted out.

## Dry-run validation is the feature to evaluate it on

The README lists validate pipelines end-to-end via dry-run among the headline capabilities, and that is the one that matters most when choosing an orchestrator.

A dry run answers a question no amount of documentation can: does this pipeline actually work against these credentials, these tables and these SQL statements. Orchestrators that only discover breakage at run time force you to debug inside a scheduler log, which is a bad place to be.

Combined with built-in data quality checks, the shape is: define the pipeline, validate it end to end without side effects, then let the quality checks assert properties on the way in.

Materializations are the other concept worth understanding before you start. A materialization declares what a pipeline's output is in the warehouse, a table or a view, and incremental tables let a pipeline process only new data rather than rebuilding. Those two concepts are where most of the value of an orchestrator lives, because they turn a directory of scripts into something a warehouse team can reason about.

The repository reflects that seriousness in other ways. There is a TRADEOFFS.md at the root, which is not common, a SECURITY.md, a CONTRIBUTING.md, an AGENTS.md and a CLAUDE.md, and a `.golangci.yml` for linting.

## CGO is required, and the Docker image shows the bill

The build is not a pure Go build and the Dockerfile is explicit about why.

The builder stage is golang 1.25.13 on trixie, and it installs git, gcc, g++, libc6-dev and curl. The comment says the C++ standard library is for DuckDB. The build itself runs with `CGO_ENABLED=1` and a build tag `no_duckdb_arrow`.

The build explicitly enables CGO and installs native build tools, although these details alone do not establish whether the resulting link is static or dynamic. If you were hoping for a single scratch-file binary you can copy anywhere, this is not that.

The final image is debian trixie-slim, and its package list is the operational requirement list: curl, git, build-essential, binutils, python3-dev, unixodbc, libodbc2 and ca-certificates.

Two of those deserve attention. build-essential and binutils are in the runtime image because Python assets need compiling, which is a consequence of running Python in isolated environments. unixodbc and libodbc2 are the ODBC stack, so the container can reach databases through a generic driver.

The image then does something that is worth copying into your own container: it creates an unprivileged user with `adduser --disabled-password`, chowns its home, switches to it with `USER bruin`, and puts the binary in that user's `.local/bin` with the PATH set accordingly. Compilation flags are exported as environment variables, `CC`, `CFLAGS` and `LDFLAGS`, so subprocess builds inherit them.

Version information is injected at link time with `-X main.version` and `-X main.commit` from build arguments, so a container can report which build it is.

## The Makefile documents why its tool versions are pinned

Build files are usually a list of commands with no explanation. This one has paragraphs.

Three tools are pinned by version variable: gci at v0.14.0, gofumpt at v0.10.0 and ruff at 0.15.4. golangci-lint is pinned at v2.11.4, and the comment above it explains the constraint in detail.

The stated reason is that a later release made its cache checkout-independent, but cached diagnostics still contain absolute paths from the checkout that produced them, which makes a shared cache unsafe across worktrees. The comment asks that the version be re-tested before bumping beyond the latest pre-change patch release.

That is a real and non-obvious failure mode: lint results cached from a different directory can report errors against files that do not exist in the current worktree. Most projects discover this by being confused once.

Two more comments handle concurrency. golangci-lint uses a single global lock in the system temporary directory while its cache supports concurrent processes, so the lint flags include `--allow-parallel-runners`, with a concurrency of 4 and a 10 minute timeout.

The lint and format targets are also split by path, with Go paths covering `cmd`, `pkg`, `semantic-engine`, the integration test files and `main.go`, and Python paths pointing at `pkg/sqlengine/codegen` and `pkg/sqlparser/codegen`, which tells you there is generated Python in the repository.

Also visible: the lint modules list is computed dynamically from every `go.mod` tracked in git, which is how the nested `semantic-engine` module gets linted too, and a macOS-specific CGO linker warning suppression sits at the bottom of the file.

## Release numbers and where Bruin is the wrong fit

The version numbering deserves a note before anything else. Releases are v0.11.779, v0.11.780 and v0.11.781, the last three published on 2026-10-14, 2026-10-14 and 2026-10-15. A three-part build number in the hundreds within a zero major version is not semantic versioning in the usual sense, and it means you should treat each release as a moving target rather than something with a stable contract.

Three cases where this is the wrong tool.

If you need a single static binary, verify the project's link mode because the shown CGO build settings do not by themselves prove whether that is possible.

If your warehouse is not in the supported platform list, you are relying on the generic ODBC path, which works but is where you will hit untested corners first.

If your team wants no runtime dependency on a Python interpreter in the execution environment, the isolated Python environments feature works against that. Bruin assumes a Python runtime is present, and the Docker image installs `python3-dev` and a build toolchain to make that assumption safe.

There is one more consideration that is about trust rather than function. The repository includes `.agents/`, `CLAUDE.md`, `AGENTS.md`, `skills/` and `examples/claude-code/`, which tells you the project is being developed with coding agents in the loop. For a data tool that holds warehouse credentials, that is worth a look at how the agent configuration is scoped before you adopt it.

The licence is Apache-2.0, which is permissive for commercial use. The last push was on 2026-10-16, so the project is moving quickly.

## Conclusion

Adopt Bruin if you want SQL, Python and R in one pipeline definition with materializations and quality checks, and you can accept a CGO-enabled binary that links DuckDB and Arrow. Skip it if you need a pure static Go binary or if your warehouse is not among the supported platforms. Verify first that your target platform's SDK is present, since the Docker image installs unixodbc and libodbc2 plus a C++ toolchain, and read the `TELEMETRY_OPTOUT` setting before you run it in a shared environment.

## FAQ

### What does Bruin do and which languages does it support?

It brings data ingestion, transformation with SQL, Python and R, and data quality checks into a single pipeline framework. Python runs in isolated environments managed by uv, ingestion goes through ingestr or Python, and the tool is written in Go.

### Does the Bruin binary need external tools to build or run?

The shown Docker build uses CGO with `CGO_ENABLED=1`, installs a C++ toolchain for DuckDB, and applies the `no_duckdb_arrow` build tag. The runtime image also installs build-essential, python3-dev, unixodbc and libodbc2.

### How does Bruin validate a pipeline before running it?

It supports validating pipelines end to end via dry-run, alongside built-in data quality checks and table or view materializations including incremental tables. The Makefile also sets `TELEMETRY_OPTOUT=1` with an empty telemetry key for local builds.

## Sources

- [bruin-data/bruin on GitHub](https://github.com/bruin-data/bruin)
- [License: Apache-2.0](https://github.com/bruin-data/bruin/blob/main/LICENSE)
- [Project website](https://getbruin.com/docs/bruin/)
- [README](https://github.com/bruin-data/bruin/blob/main/README.md)
- [Releases](https://github.com/bruin-data/bruin/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bruin-data-bruin
