Tool Migration
import { Aside } from ‘@astrojs/starlight/components’;
This guide covers migrating performance test scripts between JMeter, k6, and Gatling using perf-migrator.
When to Migrate
Section titled “When to Migrate”Common reasons to switch tools:
- JMeter → k6: Reducing infrastructure overhead (k6 uses less memory per VU), moving to code-first scripts, better CI/CD integration
- JMeter → Gatling: Scala type safety, better distributed testing, Akka-based scaling
- k6 → JMeter: Need protocol support not available in k6 (LDAP, FTP, JMS), GUI-based team
- k6/Gatling → JMeter: Legacy infrastructure requires JMX format, existing JMeter infrastructure
- Any → Any: Standardising a mixed-tool organisation on a single tool
Before You Migrate
Section titled “Before You Migrate”Audit your existing script first:
perf-lint check existing-test.jmx --format json > pre-migration-lint.jsonFix lint errors before migrating. Clean input produces cleaner output.
Basic Migration
Section titled “Basic Migration”Install perf-migrator and activate your license:
export PERF_MIGRATOR_LICENSE=your-license-keyJMeter → k6
Section titled “JMeter → k6”perf-migrator jmx2k6 load-test.jmx -o load-test.jsJMeter → Gatling
Section titled “JMeter → Gatling”perf-migrator jmx2gatling load-test.jmx -o src/test/scala/LoadTest.scalak6 → JMeter
Section titled “k6 → JMeter”perf-migrator k62jmx script.js -o load-test.jmxk6 → Gatling
Section titled “k6 → Gatling”perf-migrator k62gatling script.js -o src/test/scala/LoadTest.scalaGatling → JMeter
Section titled “Gatling → JMeter”perf-migrator gatling2jmx MySimulation.scala -o load-test.jmxGatling → k6
Section titled “Gatling → k6”perf-migrator gatling2k6 MySimulation.scala -o script.jsReview the Conversion Report
Section titled “Review the Conversion Report”Always check the report, especially for complex scripts:
perf-migrator jmx2k6 load-test.jmx -o load-test.js --html-report migration-report.htmlOpen migration-report.html in a browser. Look for:
skippedelements: parts that weren’t converted — you’ll need to add these manuallypartialstatus: elements that were converted but may need review (e.g., regex patterns, complex conditional logic)- Secrets warnings: hardcoded credentials detected in the source
JSON report:
perf-migrator jmx2k6 load-test.jmx -o load-test.js --report migration-report.jsoncat migration-report.json | jq '.skippedElements'Lint the Output
Section titled “Lint the Output”The output is automatically lint-clean, but verify:
perf-migrator jmx2k6 load-test.jmx -o load-test.js && perf-lint check load-test.jsWith perf-ecosystem.yml (integrations.migrator_validate: true), this runs automatically.
Common Manual Fixes
Section titled “Common Manual Fixes”BSF/JSR223 Samplers (JMeter → k6)
Section titled “BSF/JSR223 Samplers (JMeter → k6)”JMeter inline Groovy/BeanShell code cannot be automatically converted. The report will flag these. Equivalent k6 pattern:
// JMeter had: BeanShell Sampler with Groovy script// k6 equivalent:export default function() { // Replace inline logic with standard k6 code const timestamp = new Date().getTime(); const signature = generateSignature(timestamp); // implement in JS}CSV Data Set Config (JMeter → k6)
Section titled “CSV Data Set Config (JMeter → k6)”Converted correctly, but the CSV file path in the output is relative. Ensure the file is accessible:
// Generated output — verify this path is correctimport { SharedArray } from 'k6/data';const users = new SharedArray('users', function() { return papaparse.parse(open('./data/users.csv'), { header: true }).data;});Load Profile (JMeter → k6)
Section titled “Load Profile (JMeter → k6)”Thread Groups with ramp-up are converted to stages:
// Generated from JMeter Thread Group: 100 VUs, ramp 60s, duration 300sexport const options = { stages: [ { duration: '60s', target: 100 }, { duration: '300s', target: 100 }, { duration: '30s', target: 0 }, ],};Review the values match your intent.
Conditional Controllers (JMeter → k6)
Section titled “Conditional Controllers (JMeter → k6)”IfController and WhileController are partially converted. Complex conditions may need manual review:
// Generated from IfController: "${loginRequired}" == "true"if (__ENV.loginRequired === 'true') { // ... login requests}Batch Migration
Section titled “Batch Migration”Migrate all JMX files in a directory:
perf-migrator jmx2k6 tests/jmeter/ --batch -o tests/k6/Output naming: test-name.converted.js
Validating the Migrated Script
Section titled “Validating the Migrated Script”-
Run a smoke test with 1-2 VUs and 30 seconds:
Terminal window docker run --rm \-v $(pwd)/tests:/tests \ghcr.io/markslilley/perf-k6:latest \k6 run /tests/load-test.js -e VUS=2 -e DURATION=30s -
Compare results with the original tool against the same endpoint.
-
Upload both to perf-results-db and use perf-compare to verify equivalence:
Terminal window npx @martkos-it/perf-compare \--url http://localhost:4000 \--project your-project-uuid \--method simple \--threshold 0.15 # allow 15% variance during migration validation
Migration Checklist
Section titled “Migration Checklist”- Pre-migration lint of source script — all errors fixed
- Migrator run with
--html-report— report reviewed - Skipped elements documented and manually added
- Output script linted — zero errors
- Smoke test passes (2 VUs, 30s)
- Comparison run vs original results within acceptable variance
- CSV/data files accessible at expected paths
- Environment variables updated for new tool’s conventions
- CI pipeline updated to use new tool
- perf-migrator product page
- perf-containers — Docker images for running the migrated scripts