A picture of me.

Last Updated: 2020-05-27

Published: 2020-05-24

A Bloop Tour for Metals users

Many of the common questions I see around the Metals ecosystem have to do with Bloop. Questions like ‘What is Bloop?’, ‘What’s Bloop’s role in Metals?’, and ‘What does the Bloop CLI do?’ are somewhat commonplace. If we step outside of the Metals world, the mystery is even more enhanced. I’ve talked to seasoned Scala devs before that weren’t aware of Bloop. All this makes it a perfect candidate for this mini-series on under-appreciated Scala tools after my last Coursier post. I don’t pretend to be an expert in Bloop at all, but I’ve been lucky enough to work closely with those that are and have hopefully been able to pick up enough to help spread the word, especially in relation to Metals.

What is Bloop

First things first, taken in part from the Bloop website: Bloop is a build server and CLI tool for the Scala programming language built by the Scala Center and spearheaded by Jorge Vicente Cantero and Martin Duhem. Bloop has two main goals:

  1. Compile, test, and run Scala code as fast as possible
  2. Integrate easily with build tools, command-line applications, editors, and custom tooling

While those two points are quite clear, there are a couple other points worth noting to help with the general understanding of Bloop. Firstly, Bloop is a server, and like other servers, it responds to requests from clients. These clients can be something like Metals, communicating with Bloop via the Build Server Protocol (BSP), or Bloop CLI, which is communicating with Bloop via the Nailgun server protocol. They can be happening concurrently, caching compilations across different clients, and offering client isolation to avoid conflicts in a shared, stateful file system.

The What is Bloop portion of the website does a great job at outlining in more detail what I have listed above, along with some of the design goals of the project.

Metals and Bloop

If you’ve seen any of the presentations done about Metals, then you’ve probably seen a graphic similar to what I have below. However, the one below is a bit more simplified showing only one language client and one build tool.

BSP + LSP diagram

This diagram is meant to show Bloop’s part in the flow from build definition to your editor of choice. If you start on the left, you have your build definition in sbt for example. If you’ve used Metals before, you’ll notice that when you first open up a project you’ll be prompted to Import Your Build. What does this mean? The first time this happens, it means that Metals detects that you have no .bloop directory and therefore you need to import your build. When using sbt this means that Metals actually adds the sbt-bloop plugin to your build in project/metals.sbt. It then issues an sbt bloopInstall command which will dump out your build definition for all of your modules into JSON files. You can see this if you open up your .bloop directory in your workspace. These files contain things like your directory information, what dependencies your module has on other modules, all your classpath information, and more. Go ahead and take a look at everything in there. Once this information is gathered, Metals tells Bloop to compile your project.

At this point, if there are any errors during compilation, diagnostics are forwarded from Bloop to Metals and then to your client for you to see. If you fix the diagnostic, hit save, the save event is sent to Metals which then forwards that to Bloop to compile what has been changed. You can start to imagine the flow from the diagram above.

At this point, one of the questions you may have is how does Bloop start? Does Metals start it? Does Metals install Bloop? There can only be one Bloop server running on a machine. So when Metals is about to start, one of two things happens. Using Bloop Launcher either a Bloop server is detected and running, which Metals connects to, or the launcher starts one.

If you’ve ever used the debugging features in Metals, you have also utilized the DAP (Debug Adaptor Protocol) support that Bloop offers. You can find the entire debugging reference here.

Bloop CLI

Especially for Metals users, I highly recommend using Bloop CLI when you have a simple workflow of compiling, testing, compiling, etc. Up above I mentioned that compilations are cached for different clients. The power in this can be witnessed when you’re in Metals, have your project compiled, and can run a test via the Bloop CLI and see it start basically immediately without another compilation happening. Personally, I’ve fully moved from running tests through sbt to running them through Bloop CLI simply because of how much faster it is for me to go from executing the bloop test <project> to seeing the test run. If you run the same test through sbt you normally have both a longer startup time and also compilation that needs to happen.

Many of the things that you would imagine using like, targeting a specific test suite, watching a test suite, passing in arguments, or testing upstream projects all exist. However, there are a few differences and nuances worth pointing out.


 bloop compile $(bloop projects)
 bloop compile --cascade root
Compiling root (1 Scala source)
Compiled root (982ms)
Compiling root-test (1 Scala source)
Compiled root-test (344ms)
 bloop clean --propagate root
 bloop console root
Welcome to the Ammonite Repl 2.1.4-2-ef9b0a0 (Scala 2.12.11 Java 1.8.0_242)
 bloop projects --dot-graph | dot -Tsvg -o metals-diagram.svg && open metals-diagram.svg
metals graphviz diagram

Takeaways and Things to keep in mind

Deduplicating compilation of root from bsp client 'Metals 0.9.0+139-c169b4ce-SNAPSHOT' (since 39.439s)

I use Bloop daily, and you may be using it as well without even realizing it. It’s an incredible tool that has set the bar for how we run, compile, and test Scala code. If you haven’t yet, take some time and head on over to the Bloop webiste, give the Bloop CLI a try, and tell a friend or colleague about it.

A special thanks to Ólafur for reading this over and always providing valuable feedback.

Thanks for stopping by.