The Limits of Out-of-the-Box Gatling Integrations
In my previous projects, Gatling proved to be an excellent tool for performance testing - especially in monolithic environments. It integrated well into traditional CI pipelines, and its DSL made writing tests both expressive and maintainable.
But as our architecture evolved toward microservices and cloud-native deployments, performance testing became significantly more complex. Running realistic tests now meant dealing with Kubernetes orchestration, multiple interdependent services, diverse deployment pipelines, and APIs that changed frequently.
The open-source version of Gatling did not provide built-in support for these modern challenges. While Gatling FrontLine solves many of them, it comes with significant subscription costs. It also may introduce vendor lock-in risks, since some features are available in the enterprise version only.
Out of the box, Gatling offers integrations with popular build tools such as:
These plugins make it straightforward to embed performance tests into your build or CI workflow. It works well for smaller systems or when your performance tests live close to your codebase.
However, once you start scaling tests across multiple services, teams, and environments, these traditional build-tool integrations quickly show their limitations. That is where alternative approaches - like Scala CLI and containerization - start to make a real difference.
The Containerization Gap
Unfortunately, Gatling does not provide an official containerized solution in the open-source edition. This seems to be intentional - containerization is part of the value proposition of Gatling FrontLine, their commercial offering.
For open-source users, this leaves a gap. A few community solutions attempt to fill it, the most common being to wrap the build tool inside a Docker image (e.g. this Maven-based example). While this works, it introduces unnecessary weight and complexity, since the container needs to ship not only your tests but also the full build toolchain.
A Cleaner Approach: Executable JARs
A better alternative to shipping build tools inside the container is to package your tests as an executable JAR. To verify if it works, we have created an example implementation: gatling-in-docker.
This approach immediately solves several problems:
- The container image is much lighter.
- There is no need for build tools or cache volumes inside the container.
- Running tests becomes as simple as
java -jar tests.jar.
However, there is still room for improvement. By default, Gatling encourages using system properties to pass configuration, but this quickly becomes cumbersome:
- It can lead to a parameter explosion in
docker runcommands. - There is no straightforward way to validate that properties are correctly formatted.
A more robust alternative is to introduce configuration files. Since Gatling already uses HOCON (Human-Optimized Config Object Notation), it makes sense to stick with it. HOCON configurations are concise and can still be overridden via environment variables or system properties.
But even with HOCON, one challenge remains: type safety. With plain configs, runtime errors may only surface during execution - sometimes in ambiguous ways.
Configuration Challenges & Circe
To avoid this, we can leverage Circe - a JSON library for Scala - together with its automatic derivation features. This lets us load configuration into strongly-typed case classes, fail early if something is wrong, and get meaningful error messages. As a proof of concept, we have created a simple configuration class:
and then used it in ExampleTest:
This example is deliberately simple, but it already demonstrates the benefits of using Circe in Gatling tests:
- Fail-fast validation: configuration errors surface immediately, before any test execution.
- Clear error messages: parsing failures are explicit, making analysis much faster.
- Extensibility: the approach can be made more modular, allowing for environment-specific or test-specific configs without extra boilerplate.
In practice, this means fewer surprises during long-running performance tests and a smoother debugging experience when something goes wrong. Which, with Gatling, can be a real pain point.
Scala CLI as a Lightweight Driver
So far, we have focused solely on Docker, without mentioning scala-cli at all. That is about to change. If you would like a deeper dive into scala-cli, and how it improves over the old Scala runner, check out this blog post.
Up to this point, we have significantly improved our testing setup. However, the current process still requires building a Docker image for every change. This can be cumbersome, especially when dealing with issues like memory constraints. JVM and Docker tuning often becomes time-consuming, and the process of experimenting or debugging is far from straightforward.
This is where Scala CLI comes in.
One of its key benefits is that you do not need to build Docker images for every iteration. Or at least, not as frequently. If the only challenge you face is avoiding the image build step, switching to scala-cli alone may not justify the effort. Performance testing tends to be stable, and image building can be offloaded to the CI pipeline.
However, the ability to run code directly from GitHub gists is what makes a difference. This helps keep experimentation and iteration straightforward, making scala-cli a powerful addition to your development workflow.
As an example, we have something like this:
Now, we just call:
But what is even better is when we run it from a Github gist:
Bringing It Together: Containerized Scala-CLI Setup
This approach is a bit problematic as scala-cli is downloading all necessary dependencies (including JVM), but it can be solved by mounting the coursier cache:
Ok, but we do not want to run it locally. Our goal is to integrate it with CI infrastructure.
There is an option to use paid CI/CD Integration, but if it is not our case, we can do it in a different way. For GitHub-actions workflow, for which we have more or less out-of-the-box solution:
Or Gitlab-CI:
Conclusions
In this article, we have explored how to combine scala-cli with containerization to modernize Gatling performance testing workflows. Traditional Gatling integrations work well for simple scenarios but struggle with microservices and cloud-native deployments, while the open-source version lacks official containerization support.
It is worth acknowledging that this approach leverages the API in a way that sidesteps Gatling's official integration points. In practice, we are working around the ecosystem's design, where containerization and advanced features are reserved for Gatling FrontLine. While this creates flexibility, it also means operating outside official support channels and potentially facing compatibility issues with future Gatling releases.
Nonetheless, as a result, we can have faster iteration cycles, better error handling, and seamless CI integration without vendor lock-in or enterprise subscription costs. While Gatling Frontline remains a solid enterprise option, this approach demonstrates that open-source Gatling can be effectively modernized for contemporary workflows.
For teams already invested in the JVM ecosystem, this offers a practical path to modern performance testing without abandoning existing Gatling expertise, though with the understanding that it relies on workarounds rather than official support.




