Languages: English | 简体中文 | 日本語 | Deutsch | Español
A gRPC mock server for testing and development.
GripMock builds a mock server from your .proto files or a compiled .pb descriptor: 29 804 req/s and a 0.4 s cold start from a 19 MB image (benchmark).
- Native Runtime - Single in-process engine without runtime gRPC code generation
- Descriptor Sources - Load API from
.proto, compiled.pb, BSR modules, or gRPC reflection - Dynamic
.pbService Loading - Load compiled protobuf descriptors at runtime via API without restarts - Hot Stub Management - Create, update, and remove stubs via API/UI without server restarts
- Flexible Matching -
equals,contains,matches,glob, headers, priority, and match limits - Array-Aware Matching - Optional array-order flexibility to reduce brittle test assertions
- Dynamic Templates - Build responses from request payload, headers, and stream context
- Complete gRPC Coverage - Unary, server streaming, client streaming, and bidirectional streaming
- Error, Details, and Delay Simulation - Return realistic gRPC status codes, details (
Any), and response timing - TLS and mTLS Support - Run secure gRPC/HTTP test environments with native TLS options
- Advanced Protobuf Type Support - Handle well-known and extended protobuf types (
google.protobuf.*,google.type.*) - YAML/JSON + Schema - Author stubs in either format with JSON Schema IDE validation
- Plugin Ecosystem - Extend functions with Go plugins and matching builder image tags
- Built-in Faker Templates - Generate realistic fake person/contact/geo/network data directly in templates (
faker.*) - OpenTelemetry Tracing - OTLP tracing for gRPC and HTTP paths (
otelgrpc+otelhttp) - Prometheus Metrics (
/metrics) - Runtime/process metrics (go_*,process_*) plus GripMock metrics - Operational APIs - Health endpoints, descriptors API, stubs API, and web dashboard
- Embedded SDK - Run GripMock inside Go tests with verification helpers
- MCP API - Streamable MCP endpoint for agent and tool integrations
- Upstream Modes -
proxy,replay,capturemodes for gradual migration from live upstream services to local mocks
Full Documentation - Complete guide with examples
Deep dives on the newer surfaces: Descriptor API · Upstream Modes · Embedded SDK · Faker Reference · OpenTelemetry + Metrics · GitHub Actions · Performance Comparison
Access the web dashboard at http://localhost:4771/ to manage your stubs visually.
Choose your preferred installation method:
brew tap gripmock/tap
brew install --cask gripmockcurl -s https://raw.githubusercontent.com/bavix/gripmock/refs/heads/master/setup.sh | sh -sirm https://raw.githubusercontent.com/bavix/gripmock/refs/heads/master/setup.ps1 | iexdocker pull bavix/gripmockFor plugin builds, use the paired builder image:
docker pull bavix/gripmock:3.18.4-buildergo install github.com/bavix/gripmock/v3@latestStart with a .proto file:
gripmock service.protoAdd static stubs:
gripmock --stub stubs/ service.protoLoad API directly from Buf Schema Registry (BSR):
gripmock --stub third_party/bsr/eliza buf.build/connectrpc/elizaLoad API from live gRPC server reflection:
gripmock grpc://localhost:50051
gripmock grpcs://api.company.local:443With options:
gripmock grpc://localhost:50051?timeout=10s
gripmock grpcs://10.0.0.5:8443?serverName=api.company.local
gripmock grpc://localhost:50051?bearer=<token>Use upstream modes over reflection:
# Pure reverse proxy through GripMock
gripmock grpc+proxy://localhost:50051
# Local stubs first, then upstream fallback on matcher miss
gripmock grpc+replay://localhost:50051
# Replay + record upstream misses into GripMock stubs
gripmock grpc+capture://localhost:50051For private BSR modules:
BSR_BUF_TOKEN=<token> gripmock --stub stubs/ buf.build/acme/private-apiFor self-hosted BSR:
BSR_SELF_BASE_URL=https://bsr.company.local \
BSR_SELF_TOKEN=<token> \
gripmock --stub stubs/ bsr.company.local/team/paymentsUsing Docker:
docker run -p 4770:4770 -p 4771:4771 -p 4769:4769 \
-v $(pwd)/stubs:/stubs \
-v $(pwd)/proto:/proto \
bavix/gripmock --stub=/stubs /proto/service.proto- Port 4770: gRPC server
- Port 4771: Web UI and REST API
- Port 4769: Gateway (gRPC-web / ConnectRPC)
OTEL_ENABLED=true \
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 \
OTEL_EXPORTER_OTLP_INSECURE=true \
gripmock --stub stubs/ service.protoGET /metricsis always available- Tracing export is enabled only when
OTEL_ENABLED=true
Use the official action bavix/gripmock-action to run GripMock in CI pipelines.
name: test
on: [push, pull_request]
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Start GripMock
uses: bavix/gripmock-action@v1
with:
source: proto/service.proto
stub: stubs
- name: Run tests
run: go test ./...What the action does:
- Downloads GripMock from GitHub Releases (
latestor pinnedversion) - Starts GripMock in background and waits for readiness (
/api/health/readiness) - Exposes addresses via outputs (
grpc-addr,http-addr) for test steps - Stops GripMock automatically in the post step
More examples and full inputs/outputs: GitHub Actions guide.
The examples folder covers:
- Streaming - Server, client, and bidirectional streaming
- File Uploads - Test chunked file uploads
- Real-time Chat - Bidirectional communication
- Data Feeds - Continuous data streaming
- Authentication - Header-based auth testing
- Performance - High-throughput scenarios
Stub (universal):
# yaml-language-server: $schema=https://bavix.github.io/gripmock/schema/stub.json
# examples/projects/greeter/stub_say_hello.yaml
- service: helloworld.Greeter
method: SayHello
input:
matches:
name: ".+"
output:
data:
message: "Hello, {{.Request.name}}!" # dynamic template lives in outputNotes:
- Put dynamic templates only in
output(e.g.,data,headers,stream). - Keep
inputmatching static (no{{ ... }}inequals/contains/matches).
# Start server
go run main.go examples/projects/greeter/service.proto --stub examples/projects/greeter
# Call via grpcurl
grpcurl -plaintext -d '{"name":"Alex"}' localhost:4770 helloworld.Greeter/SayHelloExpected response:
{
"message": "Hello, Alex!"
}service: Greeter
method: SayHello
input:
equals:
name: "gripmock"
output:
data:
message: "Hello GripMock!"Priority System:
- service: UserService
method: GetUser
priority: 100 # Higher priority
input:
equals:
id: "admin"
output:
data:
role: "administrator"
- service: UserService
method: GetUser
priority: 1 # Lower priority (fallback)
input:
contains:
id: "user"
output:
data:
role: "user"Streaming Support:
service: TrackService
method: StreamData
input:
equals:
sensor_id: "GPS001"
output:
stream:
- position: {"lat": 40.7128, "lng": -74.0060}
timestamp: "2024-01-01T12:00:00Z"
- position: {"lat": 40.7130, "lng": -74.0062}
timestamp: "2024-01-01T12:00:05Z"GripMock supports dynamic templates in the output section using Go's text/template syntax.
- Access request fields:
{{.Request.field}} - Access headers:
{{.Headers.header_name}} - Client streaming context:
{{.Requests}}(slice of received messages),{{len .Requests}},{{(index .Requests 0).field}} - Bidirectional streaming:
{{.MessageIndex}}gives the current message index (0-based) - Math helpers:
sum,avg,mul,min,max,add,sub,div - Utility:
json,split,join,upper,lower,title,sprintf,int,int64,float,round,floor,ceil - Built-in faker:
faker.Person.*,faker.Contact.*,faker.Geo.*,faker.Network.*,faker.Identity.*
Important rules:
- Do not use dynamic templates inside
input.equals,input.contains, orinput.matches(matching must be static) - For server streaming, if both
output.streamandoutput.error/output.codeare set, messages are sent first and then the error is returned. Ifoutput.streamis empty, the error is returned immediately
Header Matching:
service: AuthService
method: ValidateToken
headers:
equals:
authorization: "Bearer valid-token"
input:
equals:
token: "abc123"
output:
data:
valid: true
user_id: "user123"Four matching strategies, combinable in one stub — see Matching Logic for how they compose:
input:
equals:
name: "gripmock"
age: 25
active: trueinput:
contains:
name: "grip" # Matches "gripmock", "gripster", etc.input:
matches:
email: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
phone: "^\\+?[1-9]\\d{1,14}$"input:
glob:
filename: "*.txt"
path: "/usr/local/*"GET /api/stubs- List all stubsPOST /api/stubs- Add or update stubsDELETE /api/stubs- Clear all stubsDELETE /api/stubs/{uuid}- Delete one stubPOST /api/stubs/batchDelete- Delete several stubs by IDPOST /api/stubs/search- Find the stub a request would hitPOST /api/stubs/validate- Validate stubs without storing themPOST /api/stubs/inspect- Explain why a request matches or missesGET /api/stubs/used/GET /api/stubs/unused- Matched and never-matched stubsPOST /api/descriptors- Load aFileDescriptorSetat runtimeGET /api/history- Recorded callsPOST /api/verify- Assert call countsGET /api/health/liveness- Health checkGET /api/health/readiness- Readiness check
Full reference: OpenAPI.
# Add a stub
curl -X POST http://localhost:4771/api/stubs \
-H "Content-Type: application/json" \
-d '{
"service": "Greeter",
"method": "SayHello",
"input": {"equals": {"name": "world"}},
"output": {"data": {"message": "Hello World!"}}
}'
# Search for matching stub
curl -X POST http://localhost:4771/api/stubs/search \
-H "Content-Type: application/json" \
-d '{
"service": "Greeter",
"method": "SayHello",
"data": {"name": "world"}
}'Add schema validation to your stub files for IDE support:
JSON files:
{
"$schema": "https://bavix.github.io/gripmock/schema/stub.json",
"service": "MyService",
"method": "MyMethod"
}YAML files:
# yaml-language-server: $schema=https://bavix.github.io/gripmock/schema/stub.json
service: MyService
method: MyMethodA BSR module reference can be passed straight to GripMock in place of a .proto path:
# Public BSR (default)
BSR_BUF_BASE_URL=https://buf.build
BSR_BUF_TOKEN=<token>
# Self-hosted BSR
BSR_SELF_BASE_URL=https://bsr.company.local
BSR_SELF_TOKEN=<token># Public module
gripmock buf.build/connectrpc/eliza
# Self-hosted module
gripmock bsr.company.local/team/payments:main
# With stubs
gripmock --stub stubs/ bsr.company.local/team/paymentsGripMock automatically routes modules:
buf.build/owner/repo→ uses Buf profilebsr.company.local/owner/repo→ uses Self profile
For details see BSR Documentation.
GripMock supports descriptor loading from gRPC reflection using endpoint schemes:
grpc://host:port(insecure)grpcs://host:port(TLS)
Supported query parameters:
timeout(default5s)bearer(Authorization token)serverName(TLS SNI override)
Examples:
gripmock grpc://localhost:50051
gripmock grpcs://api.company.local:443
gripmock grpcs://10.0.0.5:8443?serverName=api.company.localFull guide: gRPC Reflection Source.
Upstream modes work on top of reflection sources and define runtime behavior:
proxy- pure reverse proxyreplay- local-first + upstream fallbackcapture- replay + automatic stub recording from upstream
Mode guides:
At 500 stubs, 4 CPUs per container. Full method and numbers: Performance Comparison
| bavix | tokopedia | |
|---|---|---|
| Throughput | 29 804 req/s | 6 221 req/s |
| p99 latency | 9.44 ms | 24.08 ms |
| Startup, avg | 0.399 s | 2.205 s |
| Image size, amd64 | 19.17 MB | 226.29 MB |
| Image size, arm64 | 18.49 MB | 219.90 MB |
- Documentation - Complete guides and examples
- Testing gRPC with Testcontainers - Article by @AndrewIISM
- JSON Schema - Stub validation schema
- OpenAPI - REST API documentation
See the Contributing Guide. Changes to gRPC behaviour need integration tests in .gctf format.
MIT — see LICENSE.


