Schema-driven GraphQL performance testing, GraphQL load testing, and GraphQL client workflows in one container.
Quick Start · Features · Installation · Configuration · Architecture
GraphQL Meter turns a GraphQL schema into runnable performance tests, live dashboards, and repeatable comparisons. It is built for teams that want GraphQL performance testing without writing custom scripts or stitching together separate tools.
It ships as a single container with Locust, k6, a built-in GraphQL client, and run history for regression analysis.
| At a glance | Details |
|---|---|
| Primary use | GraphQL performance testing and GraphQL load testing |
| Secondary use | GraphQL API testing, schema discovery, and client verification |
| Delivery | Single container, no build step, no external orchestration |
| Engines | Locust and k6, isolated from the FastAPI process |
| Outputs | Live metrics, run comparisons, and trend views |
GraphQL teams usually need to solve the same problems before they can test at all:
- Write custom load scripts for every API shape.
- Manually manage test data and request variables.
- Configure authentication, TLS, and client certificates.
- Switch between multiple tools for schema discovery, execution, and comparison.
GraphQL Meter removes that setup cost by auto-discovering operations from your schema and generating everything needed to run, monitor, and compare tests.
| Capability | What it covers | Why it matters |
|---|---|---|
| Schema-driven testing | Discover queries and mutations from a GraphQL schema | Faster test setup with less manual wiring |
| Dual load engines | Locust and k6, switchable per run | Compare engine behavior on the same workload |
| Live monitoring | Throughput, error rate, and p50/p90/p95/p99 latency | See regressions while a test is running |
| Run comparison | Side-by-side delta analysis across runs | Spot performance drift quickly |
| Environment profiles | TLS/mTLS, certs, custom headers, and auth providers | Test realistic GraphQL API environments safely |
| Built-in GraphQL client | Query execution before load testing | Validate schema, auth, and responses first |
| Runtime configuration | Toggle limits and engines without restart | Adjust behavior from the UI when needed |
Paste a GraphQL schema and GraphQL Meter will parse it, discover operations, and generate type-aware test variables with smart defaults. No hand-authored test scripts required.
The wizard automatically discovers operations and allows you to configure traffic distribution:
Choose between Locust and k6 per test run. Both engines are subprocess-isolated from the main server, so they never share the FastAPI process. Compare results across engines to validate findings.
Watch throughput, response times, error rates, and per-operation breakdowns update live every 2 seconds. Interactive SVG charts render directly in the browser with no chart library dependency.
A 3-step wizard guides test setup: define global parameters, select operations with TPS percentage distribution, and review before starting. Saved configurations are reusable across runs.
Compare any two runs side-by-side with delta highlighting. View per-operation deltas and overall metrics:
View latency and throughput trends over the last N runs for any test configuration to catch regressions early:
Define multiple target environments with distinct base URLs, TLS/mTLS settings, client certificates, custom headers, and linked authentication providers. Switch between dev, staging, and production targets without reconfiguring tests:
Six auth provider types: Bearer Token, Basic Auth, API Key, OAuth2 Client Credentials, OAuth2 Password, and Custom JWT. All secrets are encrypted at rest with Fernet. Token caching is thread-safe and automatically refreshes OAuth2 flows.
Verify queries against your target API before running load tests. The split-pane editor supports variables, headers, environment resolution, auth provider resolution, saved requests, and import from test configurations:
Adjust concurrency limits, enable or disable engines, toggle debug mode, and tune polling intervals from the Settings page without restarting the server. Changes take effect immediately for the current session:
The fastest path to a running instance:
# Docker (recommended)
docker run -p 8899:8899 ghcr.io/vanditsramblings/graphql-meter:latest
# Then open http://localhost:8899
# Login: admin / admin123GraphQL Meter is ready at http://localhost:8899 with both engines enabled, k6 pre-installed, and default credentials.
Includes Python runtime, Locust, k6, and all frontend assets. Nothing else to install.
# Run with default settings
docker run -p 8899:8899 ghcr.io/vanditsramblings/graphql-meter:latest
# Run with custom configuration
docker run -p 8899:8899 \
-e MAX_CONCURRENT_RUNS=5 \
-e ENABLE_K6=true \
-e ENABLE_LOCUST=true \
-v graphql-meter-data:/app/backend/data \
ghcr.io/vanditsramblings/graphql-meter:latest
# Run with persistent data
docker run -p 8899:8899 \
-v $(pwd)/data:/app/backend/data \
ghcr.io/vanditsramblings/graphql-meter:latest
# Run with limited resources (recommended for shared/CI environments)
docker run -p 8899:8899 \
--memory=512m \
--cpus=1.0 \
-e MAX_CONCURRENT_RUNS=1 \
-v graphql-meter-data:/app/backend/data \
ghcr.io/vanditsramblings/graphql-meter:latestRequires Python 3.11 or later. k6 is auto-downloaded on first use.
# Install globally via pipx (recommended for CLI tools)
pipx install graphql-meter
graphql-meter
# Or install in a virtual environment
pip install graphql-meter
graphql-meterbrew tap vanditsramblings/tap
brew install graphql-meter
graphql-meterThe tap repository will be published alongside the first stable release. Until then, use pipx or Docker.
git clone https://github.com/vanditsramblings/graphql-meter.git
cd graphql-meter
./start.sh # macOS / Linux
# start.bat # Windows (cmd)
# .\start.ps1 # Windows (PowerShell)
make test
make lint
make typecheck
make security
make openapi
pre-commit installA Helm chart is provided in the helm/ directory for deploying to Kubernetes clusters.
# Install with default settings
helm install graphql-meter ./helm/graphql-meter
# Install with custom values
helm install graphql-meter ./helm/graphql-meter \
--set persistence.size=5Gi \
--set resources.limits.memory=2Gi
# Install with ingress enabled
helm install graphql-meter ./helm/graphql-meter \
--set ingress.enabled=true \
--set ingress.hosts[0].host=graphql-meter.example.com \
--set ingress.hosts[0].paths[0].path=/ \
--set ingress.hosts[0].paths[0].pathType=Prefix
# Upgrade an existing release
helm upgrade graphql-meter ./helm/graphql-meter
# Uninstall
helm uninstall graphql-meterThe chart includes:
- Deployment with configurable resource limits, liveness/readiness probes
- Service (ClusterIP by default, configurable)
- PersistentVolumeClaim for SQLite data and run artifacts (2Gi default)
- Ingress (optional, disabled by default)
See helm/graphql-meter/values.yaml for all configurable values.
For production, set either secret.jwtSecret or secret.existingSecret and pin a release tag or image digest instead of relying on latest.
start.sh / start.bat / start.ps1 perform the following steps:
- Creates a Python virtual environment (
.venv) - Installs the package in editable mode with dev dependencies
- Copies
.env.exampleto.envif not present - Downloads vendored frontend libraries (Preact, HTM)
- Downloads the k6 binary for your platform
- Starts the server on http://localhost:8899
Windows users can run start.bat (cmd) or .\start.ps1 (PowerShell) — both are equivalent to start.sh.
Manual setup (if you prefer not to use start.sh):
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # Edit settings as needed
python backend/app.py # Or: graphql-meterAfter starting, confirm the server is running:
curl http://localhost:8899/api/health/status
# {"status":"ok","uptime":"0h 0m 5s",...}Default login credentials:
| Username | Password | Role |
|---|---|---|
admin |
admin123 |
Full access |
maintainer |
maintainer123 |
Create, run, configure |
reader |
reader123 |
View and run tests |
All settings are controlled via environment variables or a .env file. Copy .env.example and modify as needed.
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Bind address |
PORT |
8899 |
Listen port |
DEBUG |
false |
Enable debug logging |
CORS_ORIGINS |
* |
Comma-separated allowed origins; set explicitly in production |
| Variable | Default | Description |
|---|---|---|
ENCRYPTION_KEY |
(auto) | Fernet key for encrypting auth provider secrets. Auto-derived from JWT_SECRET if empty. |
| Variable | Default | Description |
|---|---|---|
MAX_CONCURRENT_RUNS |
3 |
Maximum simultaneous test runs |
STATS_POLL_INTERVAL_SEC |
2 |
How often engines write stats (seconds) |
MAX_ERROR_BUFFER |
500 |
Maximum error lines kept in memory per run |
MAX_RUN_HISTORY |
200 |
Maximum runs retained in history |
CHART_HISTORY_RUNS |
10 |
Runs with full chart data retained |
| Variable | Default | Description |
|---|---|---|
ENABLE_K6 |
true |
Enable the k6 load testing engine |
ENABLE_LOCUST |
true |
Enable the Locust load testing engine |
K6_BINARY_PATH |
(auto) | Path to k6 binary. Auto-detected/downloaded if empty. |
| Variable | Default | Description |
|---|---|---|
WORKER_THREADS |
4 |
Background worker thread count |
UVICORN_WORKERS |
1 |
Uvicorn process workers |
DASHBOARD_POLL_SEC |
5 |
Dashboard refresh interval (frontend hint) |
RUNNING_TEST_POLL_SEC |
2 |
Live test page refresh interval (frontend hint) |
| Variable | Default | Description |
|---|---|---|
DB_PATH |
backend/data/portal.db |
SQLite database file path |
Environment variables (highest priority):
export MAX_CONCURRENT_RUNS=5
graphql-meterDocker environment:
docker run -e ENABLE_K6=false -p 8899:8899 ghcr.io/vanditsramblings/graphql-meter.env file (loaded automatically from working directory):
MAX_CONCURRENT_RUNS=5
ENABLE_K6=true
ENABLE_LOCUST=trueRuntime overrides (admin only, via UI Settings page or API):
curl -X PUT http://localhost:8899/api/health/config \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"max_concurrent_runs": 5, "enable_k6": false}'Runtime changes persist until the server is restarted.
Navigate to Test Configs and use the 3-step wizard:
- Global Parameters: Name your test, set target host, user count, ramp-up period, and duration. Paste your GraphQL schema.
- Operations: Select which queries/mutations to include. Set TPS percentage for each (must total 100%). Configure test data and delay start times.
- Review: Choose engine (Locust or k6), enable debug mode or cleanup-on-stop, then save or start immediately.
From the Test History page, start any saved configuration. The live monitoring view shows:
- Real-time throughput and response time charts
- Per-operation stats table (requests, failures, latency percentiles)
- Scrollable error log
- Stop button with confirmation
- Test History: Browse completed, failed, and running tests with sortable tables
- Compare: Select two runs for side-by-side delta analysis
- Trends: View latency and RPS over the last N runs for any configuration
- Export: Download self-contained HTML reports for any run
Create environment profiles with TLS/mTLS settings, client certificates, custom headers, and linked auth providers. Switch between environments when starting tests.
Schema changes are managed with Alembic. On first install the database is created automatically by the application. For subsequent schema changes:
# Apply pending migrations
make migrate
# Or directly:
source .venv/bin/activate
alembic upgrade head
# Create a new migration after a schema change
alembic revision --autogenerate -m "describe_your_change"
# Stamp an existing database at the baseline (pre-Alembic installs)
alembic stamp 0001The Alembic configuration lives in alembic.ini and alembic/. It reads DB_PATH from the environment (default: backend/data/portal.db).
graphql-meter/
+-- backend/
| +-- app.py # FastAPI entry, CORS, plugin loading, static files
| +-- config.py # Pydantic BaseSettings (.env)
| +-- cli.py # CLI entry point (graphql-meter command)
| +-- k6_manager.py # k6 binary auto-detection / download
| +-- vendor_manager.py # Frontend vendor library provisioning
| +-- core/ # Plugin base, registry, cache
| +-- plugins/ # 12 auto-discovered plugins
| +-- models/ # Pydantic models
| +-- locust_engine/ # Locust subprocess: worker, token manager
| +-- k6_engine/ # k6 subprocess: script generator, metrics parser
| +-- data/ # SQLite DB + per-run IPC directories
+-- frontend/
| +-- index.html # Importmap, ES modules entry
| +-- app.js # Root: Auth -> Router -> Layout -> Pages
| +-- styles.css # Dark theme, CSS custom properties
| +-- lib/ # API client, auth context, router, feature flags
| +-- components/ # 15+ reusable components (charts, tables, modals)
| +-- pages/ # 11 route pages
| +-- vendor/ # Vendored Preact, HTM (.mjs)
+-- tests/ # 126+ pytest unit tests
| Component | Technology | Notes |
|---|---|---|
| Backend | Python 3.12+ / FastAPI / Uvicorn | Plugin-based, async |
| Database | SQLite (WAL mode) | Thread-local connections |
| Frontend | Preact 10 + HTM 3 | No build step, ES modules |
| Load Engine | Locust + k6 | Subprocess-isolated |
| Auth | Manual JWT HS256 | 3 roles, 12 feature flags |
| Encryption | Fernet AES-128-CBC | PBKDF2-SHA256 key derivation |
| Package | Version | Purpose |
|---|---|---|
| FastAPI | >=0.115.0 | Web framework and REST API |
| Uvicorn | >=0.32.0 | ASGI server |
| Pydantic | >=2.10.0 | Data validation, settings |
| Locust | >=2.32.0 | Python-based load testing engine |
| graphql-core | >=3.2.5 | GraphQL schema parsing |
| httpx | >=0.28.0 | HTTP client for GraphQL client |
| cryptography | >=44.0.0 | Fernet encryption for secrets |
| psutil | >=6.1.0 | System resource monitoring |
| requests | >=2.32.0 | HTTP client for auth flows |
| PyYAML | >=6.0.2 | Configuration parsing |
| cachetools | >=5.5.0 | TTL cache for tokens |
| Binary | Version | Required | Notes |
|---|---|---|---|
| k6 | v0.54.0 | Optional | Auto-downloaded on first use. Set K6_BINARY_PATH for custom location. Disable with ENABLE_K6=false. |
| Library | Version | Purpose |
|---|---|---|
| Preact | 10.24.3 | UI framework (3KB alternative to React) |
| HTM | 3.1.1 | Tagged template JSX alternative |
| Package | Version | Purpose |
|---|---|---|
| pytest | >=8.0 | Test framework |
| httpx | >=0.28.0 | Test HTTP client |
source .venv/bin/activate
python -m pytest tests/ -q --tb=short126+ tests cover storage, auth, environments, auth providers, GraphQL client, and test config CRUD with full RBAC validation.
GraphQL Meter is built on the shoulders of these open-source projects:
- Locust -- Scalable Python load testing framework by the Locust community
- k6 -- Modern load testing tool by Grafana Labs
- FastAPI -- High-performance Python web framework by Sebastian Ramirez
- Preact -- Fast 3kB React alternative by Jason Miller
- HTM -- JSX-like syntax in tagged templates by Jason Miller
- graphql-core -- GraphQL implementation for Python
- SQLite -- The most widely deployed database engine
UI design inspired by Grafana and k6 Studio dark themes.
Apache 2.0 -- see LICENSE.
- Issues: GitHub Issues
- Discussions: GitHub Discussions









