Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gatling/gatling.io-doc/llms.txt

Use this file to discover all available pages before exploring further.

Gatling’s gRPC support lets you load test high-performance RPC services built on gRPC, Google’s open-source framework that runs over HTTP/2. Whether your service exposes unary calls, server-streaming, client-streaming, or bidirectional-streaming methods, Gatling can model each interaction pattern faithfully—measuring latency, throughput, and error rates at scale. Under the hood, Gatling uses gRPC-Java and requires Protocol Buffers descriptors (generated from .proto files) to serialize messages.
The Gatling gRPC component is distributed under the Gatling Enterprise Component License. When run with the Community Edition, tests are limited to 5 users and 5 minutes. Unlimited usage requires Gatling Enterprise.

Project Setup

Gatling’s gRPC plugin is not included by default. Add the dependency alongside your standard Gatling dependencies.
1

Add the gRPC dependency

For Java or Kotlin (Maven):
<dependency>
  <groupId>io.gatling</groupId>
  <artifactId>gatling-grpc</artifactId>
  <scope>test</scope>
</dependency>
For Java or Kotlin (Gradle):
testImplementation "io.gatling:gatling-grpc:#{gatlingVersion}"
For JavaScript / TypeScript:
npm install @gatling.io/grpc
For Scala (sbt):
libraryDependencies += "io.gatling" %% "gatling-grpc" % gatlingVersion % Test
2

Configure Protobuf code generation

gRPC uses Protocol Buffers to serialize messages. You need to generate method descriptor and message classes from your .proto files.Scala (sbt) — ScalaPB:
// project/plugins.sbt
addSbtPlugin("com.thesamet" % "sbt-protoc" % "1.0.8")
libraryDependencies ++= Seq(
  "com.thesamet.scalapb" %% "compilerplugin" % "0.11.20"
)

// build.sbt
Test / PB.targets := Seq(
  scalapb.gen() -> (Test / sourceManaged).value
)
libraryDependencies ++= Seq(
  "com.thesamet.scalapb" %% "scalapb-runtime"      % scalapb.compiler.Version.scalapbVersion % "protobuf",
  "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion % "test"
)
For JavaScript/TypeScript, place .proto files in the protobuf/ directory. See the demo project for full examples.
3

Add imports to your simulation

The gRPC SDK must be imported manually:
import io.gatling.javaapi.grpc.*;
import static io.gatling.javaapi.grpc.GrpcDsl.*;
A complete demo project is available for Java (Maven/Gradle), Kotlin (Maven/Gradle), Scala (sbt), JavaScript, and TypeScript, including a runnable demo server.

Protocol Configuration

Use the grpc object to configure the gRPC protocol. In modern Gatling gRPC, connection settings are expressed as server configurations rather than being applied directly to the protocol object.

Server Configurations

A server configuration defines target address and connection options for one or more gRPC servers. When multiple configurations are defined, the first one is used as the default.
GrpcProtocolBuilder grpcProtocol = grpc
  .forAddress("grpc.example.com", 443)
  .useInsecureTrustManager();
Server configuration names must be unique across your simulation.

Target (Required)

Every server configuration must declare a remote address. Use either forAddress (host + port) or forTarget (full URI/FQDN):
grpc.forAddress("grpc.example.com", 443)

Channel Options

By default every virtual user maintains its own gRPC channel.

shareChannel

Share a single channel across all virtual users. Note that underlying connection count does not scale automatically.
grpc.forAddress("host", 50051).shareChannel()

useChannelPool

Use a pool of channels to allow more concurrent HTTP/2 connections—useful when combined with shareChannel.
grpc.forAddress("host", 50051)
    .shareChannel()
    .useChannelPool(4)

Encryption and Authentication

grpc.forAddress("host", 50051).usePlaintext()
Disables encryption entirely. Suitable for internal testing or local services.

Shared TLS Context

To amortize TLS handshake overhead while still using per-user channels:
grpc.forAddress("host", 50051).shareSslContext()

Call Credentials

Apply io.grpc.CallCredentials to every request (overridable per-call):
grpc.forAddress("host", 50051).callCredentials(myCallCredentials)

Authority Override

Override the authority used for TLS and HTTP virtual hosting:
grpc.forAddress("host", 50051).overrideAuthority("override.example.com")

Headers

Headers are set per-stream. Adding the same key a second time appends a second value rather than replacing the first.
grpc.forAddress("host", 50051).asciiHeader("x-custom-header", "value")

Load Balancing

When a name resolver returns multiple addresses, configure a load balancing policy:

Round-Robin

grpc.forAddress("host", 50051)
    .useRoundRobinLoadBalancingPolicy()

Pick First

grpc.forAddress("host", 50051)
    .usePickFirstLoadBalancingPolicy()

Pick Random

grpc.forAddress("host", 50051)
    .usePickRandomLoadBalancingPolicy()
Bundled with Gatling gRPC; not a standard gRPC policy.

Custom Policy

grpc.forAddress("host", 50051)
    .useCustomLoadBalancingPolicy("my-policy")
// or with JSON config:
grpc.forAddress("host", 50051)
    .useCustomLoadBalancingPolicy("my-policy", jsonConfig)

Unmatched Inbound Message Buffer

By default, unmatched inbound messages are discarded. Enable buffering for later processing:
grpc.forAddress("host", 50051).unmatchedInboundMessageBufferSize(100)

gRPC Method Types

gRPC defines four method types. All methods start with grpc("requestName") and take a MethodDescriptor generated from your .proto file.
// Typical generated descriptor reference
ExampleServiceGrpc.getExampleMethod()

Unary

A single request followed by a single response. Gatling automatically manages the stream lifecycle.
grpc("get user")
  .unary(ExampleServiceGrpc.getGetUserMethod())
  .send(GetUserRequest.newBuilder().setId("user-1").build())
  .check(statusCode().is(Status.Code.OK))

Server Streaming

The client sends one message; the server streams back multiple responses. Use awaitStreamEnd to wait for the server to close the stream. Assign the stream to a variable so you can reference it in multiple exec steps:
// Define the stream (checks are attached before send)
GrpcServerStreamingServiceBuilder<StreamRequest, ExampleResponse> stream =
  grpc("server stream")
    .serverStream(ExampleServiceGrpc.getServerStreamMethod())
    .check(response(ExampleResponse::getMessage).saveAs("lastMessage"));

// Execute: send opens the stream; awaitStreamEnd waits for server close
exec(
  stream.send(StreamRequest.newBuilder().build()),
  stream.awaitStreamEnd()
)
When running multiple concurrent server streams per user, assign explicit names:
GrpcServerStreamingServiceBuilder<R, Resp> stream1 =
  grpc("stream A").serverStream(method, "streamA");
GrpcServerStreamingServiceBuilder<R, Resp> stream2 =
  grpc("stream B").serverStream(method, "streamB");

Client Streaming

The client sends multiple messages; the server replies once after the client half-closes.
// Open the stream
grpc("client stream").clientStream(method).start()
// Send messages
grpc("send 1").clientStream(method).send(msg1)
grpc("send 2").clientStream(method).send(msg2)
// Signal end of client messages and wait for server response
grpc("half close").clientStream(method).halfClose()
grpc("await end").clientStream(method).awaitStreamEnd()

Bidirectional Streaming

Both sides send multiple messages. Lifecycle: startsend (multiple) → halfCloseawaitStreamEnd.
grpc("bidi start").bidiStream(method).start()
grpc("bidi send").bidiStream(method).send(message)
grpc("bidi half close").bidiStream(method).halfClose()
grpc("bidi end").bidiStream(method).awaitStreamEnd()

Methods Reference

Per-Request Options

All method types support these options:
OptionMethodDescription
Override serverserverConfiguration("name")Use a named server config instead of the default
ASCII headersasciiHeader(key, value) / asciiHeaders(map)Add ASCII metadata headers
Binary headersbinaryHeader(key, bytes) / binaryHeaders(map)Add binary metadata headers
Custom marshallerheader(key, value)Add header with a custom Metadata.Key
Call credentialscallCredentials(creds)Override per-call credentials
DeadlinedeadlineAfter(duration)Set a deadline computed just before the call starts
Checkscheck(...)Attach response checks

Message Response Time Policy (Streaming)

For server and bidirectional streaming, control how per-message response time is measured:

FromStreamStartPolicy (default)

Time measured since the stream was opened. Produces increasing values for long-lived streams.

FromLastMessageSentPolicy

Time measured since the last outbound message was sent. Useful for request-reply patterns.

FromLastMessageReceivedPolicy

Time measured since the previous inbound message was received.

Custom function

Return a custom Instant (or null/None to ignore the response time for that message).
grpc("bidi stream")
  .bidiStream(method)
  .messageResponseTimePolicy(MessageResponseTimePolicy.fromLastMessageSent())

Processing Unmatched Messages

For server and bidirectional streams, buffer and process messages that were not matched by checks. Call processUnmatchedMessages on a pre-created stream variable:
GrpcBidirectionalStreamingServiceBuilder<Req, Resp> stream =
  grpc("name").bidiStream(method);

// Process unmatched messages at a point during the stream lifecycle
exec(stream.processUnmatchedMessages((messages, session) -> {
  // messages sorted oldest-first (GrpcInboundMessage instances)
  return session.set("messages", messages);
}))

// Or combine with awaitStreamEnd to process remaining messages when the stream ends
exec(stream.awaitStreamEndAndProcessUnmatchedMessages((messages, session) ->
  session.set("messages", messages)))
The buffer resets when an outbound message is sent or processUnmatchedMessages is called. Enable buffering via unmatchedInboundMessageBufferSize on the protocol.

Cancel Stream

Abort a stream and prevent further processing. Call cancel() on a pre-created stream variable:
GrpcBidirectionalStreamingServiceBuilder<Req, Resp> stream =
  grpc("name").bidiStream(method);

exec(stream.cancel())

Checks

Checks can target four components of a gRPC response. Priority order (regardless of definition order): Status → Headers → Trailers → Message.
If no explicit status check is defined, Gatling applies an implicit check that verifies the status code is Status.Code.OK.

Status Checks

// Status code
.check(statusCode().is(Status.Code.OK))
.check(statusCode().not(Status.Code.UNAVAILABLE))

// Status description (optional)
.check(statusDescription().is("expected description"))
.check(statusDescription().isNull())

// Status cause (optional Throwable)
.check(statusCause().isNull())

Header and Trailer Checks

// ASCII header by name
.check(asciiHeader("content-type").is("application/grpc"))

// Binary header
.check(binaryHeader(myBinaryKey).is(expectedBytes))

// Multi-valued header as a list
.check(asciiHeader("x-multi").isEL("#{expectedList}"))

// Trailers work identically
.check(asciiTrailer("grpc-status-message").exists())
Binary header and trailer keys must end with the suffix -bin as required by the gRPC specification.

Message / Response Checks

// Extract a field from the response message
.check(response(ExampleResponse::getResultCode).is(200))

// Save a field for use in later requests
.check(response(ExampleResponse::getToken).saveAs("authToken"))
When using Scala or Java lambdas, the parameter type cannot be inferred and must be specified explicitly.

Check Scope by Method Kind

Checks are defined after send:
grpc("unary call")
  .unary(method)
  .send(request)
  .check(statusCode().is(Status.Code.OK))
  .check(response(Resp::getValue).saveAs("result"))
It is not currently possible to apply different checks to different incoming messages in the same stream. Using saveAs in a message check will overwrite previously saved values each time a message is received.

Build docs developers (and LLMs) love