CLI tool
sorbet/sorbet avatar
sorbet/sorbet

Sorbet: A Gradual Type Checker for Ruby, Built in C++

A fast, powerful type checker designed for Ruby. internals.md There is also a talk online that describes Sorbet's high-level architecture and the reasons why it's fast: Fast type checking for Ruby Building Sorbet There are multiple ways to build sorbet.

3,800 stars630 forksC++Apache-2.0

At a glance

What is it?
Sorbet is a Ruby type checker from Stripe, written in C++ and distributed under Apache-2.0. It targets large, existing Ruby codebases that cannot be rewritten, and the repository's own README is aimed at people building it from source rather than at application developers.
Who is it for?
Sorbet fits teams with a large Ruby codebase that want type errors reported without a rewrite, and who accept that the repository's own README is a contributor guide built around Bazel. It does not fit small scripts, or anyone hoping for a one-line install: the documented path is brew install bazel autoconf coreutils parallel, then ./bazel build //main:sorbet --config=dbg, and the README does not document rollback or removal.
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 4 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Sorbet targets: Ruby without a rewrite

Ruby is dynamically typed, so a method call that passes the wrong kind of object fails at runtime, in production, on the code path that happens to execute. Sorbet's answer is a gradual type checker: annotations are optional and can be added file by file, so an existing codebase does not need a flag day. The README states this directly in its design principles, listing "Compatible with Ruby" and "Can be adopted gradually" as two of six guidelines. The fourth principle is explicit that Sorbet does not introduce new syntax, on the grounds that existing Ruby syntax keeps existing tooling (editors and the like) working.

The audience is narrow and specific. Sorbet is built for large, long-lived Ruby codebases and their teams, not for a weekend script. The README's fifth principle says the project cares about scaling "on all axes: execution speed, number of collaborators, lines of code, codebase age." That is a design constraint, not marketing: a checker that takes minutes on a monorepo gets turned off, so speed is treated as a correctness requirement for adoption. The README also points readers to the public docs at sorbet.org and to an online playground at sorbet.run, which is where a prospective user should start. The repository README itself is a contributor document, and it says so.

How Sorbet is put together: phases, payload, and RBI files

The README points to docs/internals.md for the architecture and to a talk titled "Fast type checking for Ruby" for the reasoning behind the speed. The top-level repository layout shows the pipeline as directories: parser/, ast/, namer/, resolver/, infer/, cfg/, and core/. Read in that order, they describe a conventional compiler front end: parse Ruby source into an AST, resolve names, then infer types over a control flow graph.

Two directories matter for how Sorbet handles code it cannot see. payload/ holds the bundled type information for Ruby's standard library and core, so a project does not have to describe String or Array itself. rbi/ holds the RBI format, which is how type signatures are expressed outside the source being checked. There is also an rbs/ directory, and gems/ and packager/ sit alongside them, which is where the gem-related tooling lives. definition_validator/ is a separate pass, which suggests that checking whether a signature is well formed is distinct from checking whether the code matches it.

The repository also contains emscripten/, which is consistent with the browser playground at sorbet.run, and vscode_extension/ with an LSP test section in the README. The README's table of contents lists tests for "Find Definition", "Find All References", "Go to Type Definition", hover, completion, workspace symbols, "Go to Implementation", rename constant, and incremental type checking. That is a language server, not just a command-line checker, and the LSP tests are part of the repository's test surface.

Building Sorbet from source with Bazel

The README opens with a Quickstart, and it is a build guide. The first step installs the build dependencies with Homebrew, which means the documented path assumes macOS. The second step clones the repository. The third builds the binary, and the fourth runs it against an inline expression.

bash
brew install bazel autoconf coreutils parallel
git clone https://github.com/sorbet/sorbet.git
cd sorbet
./bazel build //main:sorbet --config=dbg
bazel-bin/main/sorbet -e "42 + 'hello'"

The build produces an executable at bazel-bin/main/sorbet. The last command passes a Ruby expression with -e, and since 42 + 'hello' is a type error, the reader should expect Sorbet to report it rather than print a value. The README notes there are multiple ways to build sorbet and calls this one the most common.

Build flags change what you get. --config=dbg is described as the most common development config, with good stack traces and all ENFORCE checks enabled. --config=sanitize links in UBSan and ASan to catch memory and undefined-behavior errors, at the cost of a substantially larger and slower binary. --config=static-libs forces static linking, which the README says Sorbet already uses in release builds, while development builds default to dynamic linking for faster build times. --config=release-mac and --config=release-linux are described as the exact release configuration shipped to users. Optimizations are separate: -c opt enables clang optimizations. The README states the flags are not mutually exclusive, and gives --config=dbg --config=sanitize as a common pairing when debugging.

One documented failure mode is worth quoting because it is common: "(Mac) Xcode version must be specified to use an Apple CROSSTOOL". The README attributes it to an Xcode upgrade and says developer tools must be installed, the Xcode license accepted, and the active command line tools directory pointed at an installed Xcode, starting with xcode-select --install.

Where Sorbet is the wrong tool

The README's own principles contain the sharpest limitation. Principle three reads: "As simple as possible, but powerful enough", and continues that the project is "not strong believers in super-complex type systems." If your Ruby relies on heavy metaprogramming, dynamic method definitions, or DSLs that generate methods at load time, Sorbet's model will not see through all of it. The team chose that boundary deliberately in exchange for a system users can learn, so it is a trade-off rather than a defect, but it is the trade-off that decides adoption.

The second limitation is the build itself. The documented quickstart requires Bazel, autoconf, coreutils, and parallel, and produces a binary through bazel-bin. That is a contributor workflow. Anyone expecting the repository README to be an application-level install guide will not find one; the README directs users to sorbet.org for the public docs, and the repository's own guidance is about building and testing the compiler. A team that only wants to run the checker should be looking at the distributed release artifacts, not this build path.

Third, the README does not document rollback or removal. There is no described procedure for taking Sorbet back out of a codebase or undoing annotations. The design principle of gradual adoption implies you can stop partway, but the repository does not spell out what that looks like in practice. Treat that as an open question to resolve before a large rollout.

Sorbet compared with RBS and Steep

The repository contains an rbs/ directory, which is a direct acknowledgement of the other type-signature format in the Ruby ecosystem. RBS is Ruby's signature language, and Steep is a checker built around it. The difference in approach is where types live. Sorbet's RBI files and its inline signatures sit alongside the code being checked, and the README's internals doc and payload/ directory describe a compiler that bundles its own view of the standard library. An RBS-based toolchain keeps signatures in separate .rbs files that describe the Ruby code from outside.

That distinction has practical consequences. Sorbet's model lets a signature sit next to the method it describes, which the README's first principle favors: annotations are treated as beneficial because "they make code more readable and predictable." An external signature file keeps the Ruby source untouched, which suits projects unwilling to modify application code at all. Neither is strictly better; the choice is whether you want types interleaved with implementation or kept in a parallel tree.

The second difference is the implementation language. Sorbet is C++, as the repository's primary language field and its parser/, infer/, and cfg/ directories indicate, and the README points to a talk about why it is fast. A pure-Ruby checker has a different performance ceiling on the same hardware. The README does not publish benchmark numbers, so treat the speed claim as a design goal described in that talk rather than a measured figure you can compare.

Maintenance, releases, and the Apache-2.0 licence

The last push to the default branch master was on 2026-08-27, and the most recent release listed is 0.6.13454.20260827162830-ef28fbbd0, dated the same day. Two earlier releases, 0.6.13453.20260827153016-8b0a71ff8 and 0.6.13452.20260827121448-b0e749cd0, carry timestamps a few hours apart on 2026-08-27. The version scheme encodes a build number, a timestamp, and a commit hash, and the pace visible in those three entries is several builds per day. The repository is not archived.

That release cadence has an upgrade cost worth naming: if you pin to a specific build string, you are pinning to something that moves daily, and the README does not describe a stable or long-term-support channel. There is a sorbet_version/ directory in the repository, which is where version handling lives, but the README does not document a compatibility policy across those builds. Plan for the version string being a moving target.

Sorbet is licensed under Apache-2.0, and the repository carries both LICENSE and NOTICE files, which is the conventional Apache-2.0 layout. The NOTICE file matters for redistribution: Apache-2.0 expects attribution notices to travel with the work. There is also an ACKNOWLEDGEMENTS.md at the top level. This is a description of the files present, not legal advice; if you are redistributing Sorbet inside a product, read LICENSE and NOTICE yourself or with counsel. The permissive terms are the reason a company can embed a checker like this without a copyleft obligation, which is presumably why the project chose them.

Editorial conclusion

Sorbet fits teams with a large Ruby codebase that want type errors reported without a rewrite, and who accept that the repository's own README is a contributor guide built around Bazel. It does not fit small scripts, or anyone hoping for a one-line install: the documented path is brew install bazel autoconf coreutils parallel, then ./bazel build //main:sorbet --config=dbg, and the README does not document rollback or removal. Verify the public docs at sorbet.org and the docs/internals.md file before committing, because the repository itself assumes you are building the compiler, not adopting it.

Frequently asked questions

What is Sorbet and what does it do for a Ruby project?

Sorbet is a type checker designed for Ruby, written in C++ and licensed under Apache-2.0. The README describes it as aiming to be easy to add to existing codebases with gradual types, and fast to respond with errors and suggestions.

How do I install Sorbet from source?

The README's Quickstart installs the dependencies with brew install bazel autoconf coreutils parallel, clones the repository, and builds with ./bazel build //main:sorbet --config=dbg. The resulting executable is at bazel-bin/main/sorbet.

Can Sorbet be adopted gradually in an existing codebase?

Yes. "Can be adopted gradually" is one of the six user-facing design principles in the README, which states that adoption cannot require every team or project to move at once. The README does not document a rollback or removal procedure.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Community notes

Community notes