Skip to content

Tool Migration

This guide covers migrating performance test scripts between JMeter, k6, and Gatling using perf-script-studio.

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

Audit your existing script first:

Terminal window
perf-lint check existing-test.jmx --format json > pre-migration-lint.json

Fix lint errors before migrating. Clean input produces cleaner output.

Install perf-script-studio and activate your licence:

Terminal window
export PERF_SCRIPT_STUDIO_LICENSE=your-license-key
Terminal window
perf-script-studio jmx2k6 load-test.jmx -o load-test.js
Terminal window
perf-script-studio jmx2gatling load-test.jmx -o src/test/scala/LoadTest.scala
Terminal window
perf-script-studio k62jmx script.js -o load-test.jmx
Terminal window
perf-script-studio k62gatling script.js -o src/test/scala/LoadTest.scala
Terminal window
perf-script-studio gatling2jmx MySimulation.scala -o load-test.jmx
Terminal window
perf-script-studio gatling2k6 MySimulation.scala -o script.js

Always check the report, especially for complex scripts:

Terminal window
perf-script-studio jmx2k6 load-test.jmx -o load-test.js --html-report migration-report.html

Open migration-report.html in a browser. Look for:

  • skipped elements: parts that weren’t converted — you’ll need to add these manually
  • partial status: 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:

Terminal window
perf-script-studio jmx2k6 load-test.jmx -o load-test.js --report migration-report.json
cat migration-report.json | jq '.skippedElements'

The output is automatically lint-clean, but verify:

Terminal window
perf-script-studio jmx2k6 load-test.jmx -o load-test.js && perf-lint check load-test.js

With perf-ecosystem.yml (integrations.migrator_validate: true), this runs automatically.

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
}

Converted correctly, but the CSV file path in the output is relative. Ensure the file is accessible:

// Generated output — verify this path is correct
import { SharedArray } from 'k6/data';
const users = new SharedArray('users', function() {
return papaparse.parse(open('./data/users.csv'), { header: true }).data;
});

Thread Groups with ramp-up are converted to stages:

// Generated from JMeter Thread Group: 100 VUs, ramp 60s, duration 300s
export const options = {
stages: [
{ duration: '60s', target: 100 },
{ duration: '300s', target: 100 },
{ duration: '30s', target: 0 },
],
};

Review the values match your intent.

IfController and WhileController are partially converted. Complex conditions may need manual review:

// Generated from IfController: "${loginRequired}" == "true"
if (__ENV.loginRequired === 'true') {
// ... login requests
}

Migrate all JMX files in a directory:

Terminal window
perf-script-studio jmx2k6 tests/jmeter/ --batch -o tests/k6/

Output naming: test-name.converted.js

  1. 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
  2. Compare results with the original tool against the same endpoint.

  3. Report on both runs and compare them, to check the converted script measures what the original did:

    Terminal window
    perf-report -i original-results.jtl --tool jmeter -o original.json
    perf-report -i converted-results.json --tool k6 -o converted.json
    perf-report compare --baseline original.json --current converted.json

    Treat a difference as a question about the conversion, not as a regression in the application. Comparing one run against one run is weak evidence — it is enough to catch a script that is doing something obviously different, and not enough to certify equivalence.

  • 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