Convert LoadRunner &
NeoLoad Scripts
in Minutes

PerfBrains automatically converts performance test scripts to Gatling, JMeter, BlazeMeter and Azure Load Testing — with full correlation detection, validated output, and zero re-scripting.

Trusted by performance engineers at Fortune 500 companies  ·  SOC 2 compliant  ·  On-premise available

perfbrains — convert
$ perfbrains convert --source checkout.log --lrp CheckoutFlow.lrp --target gatling_oss
 
✓ Parsed 247 requests across 3 VUs
✓ Fused log + .lrp — fidelity: HIGH
✓ Detected 14 correlation extractors (11 HIGH, 3 MEDIUM)
✓ Generated 4 feeder CSV files
✓ Emitted CheckoutFlowSimulation.scala
 
✓ Conversion complete — 44.2s  |  Validation score: 96%
 
$
LoadRunner 12.x — 2023 · NeoLoad 6+ & YAML · Proxy HAR files · Gatling OSS 3.9+ · Gatling Enterprise · JMeter 5.6+ · BlazeMeter · Azure Load Testing · JSONPath extractors · Boundary extractors · Header extractors · Regex extractors · CI/CD ready · On-premise deploy · LoadRunner 12.x — 2023 · NeoLoad 6+ & YAML · Proxy HAR files · Gatling OSS 3.9+ · Gatling Enterprise · JMeter 5.6+ · BlazeMeter · Azure Load Testing ·

Migration is costing
you weeks per script

Every performance engineer who has tried to migrate a LoadRunner script to Gatling manually knows the pain. Correlations that took months to tune, re-scripted from scratch. Think times re-calibrated by hand. Feeder files rebuilt from logs.

Correlation logic is opaque

LoadRunner's .lrp correlation rules don't map cleanly to Gatling or JMeter. Engineers must reverse-engineer each extractor from request/response logs — a multi-day process per script.

Think times and pacing are lost

Think time policies (replay / random / ignore) and pacing configurations live in the .lrp file. Importing only the log means every think time must be re-configured manually.

No way to verify correctness

After spending days on a manual migration, how do you know the converted script replays the original flow correctly? Most teams don't find out until the first load test run fails.

2–5
days per script,
manually migrated
$4,800
avg engineer cost per
script migration
20 min
to convert the same
script with PerfBrains
96%
avg mock validation
score on first run

Five stages. One command.

Upload your files and PerfBrains' conversion pipeline handles everything — from parsing multi-VU logs to generating production-ready scripts with verified correlations.

01

Dependency Validator

Detects format, version, protocol, and log level. Hard-blocks unsupported inputs with clear error messages.

02

Multi-Input Parsers

Parses .log, .lrp, .c, .nlp, .yaml, and .har. Each parser extracts the full request model including bodies and headers.

03

Fusion Engine

Merges all inputs using strict precedence rules. LRP rules override heuristics. NeoLoad extractors override cross-VU diff.

04

Correlation Engine

Detects dynamic values across VU threads. Generates JSONPath, boundary, regex, and header extractors with confidence scores.

05

Emitters

Produces Gatling Scala DSL or JMeter XML with feeder CSVs, think times, transactions, and env-var base URLs.

Everything a migration
actually needs

Not a stub generator. PerfBrains produces output you can run immediately, with correlations verified and performance tested.

Multi-input fusion

Upload log + .lrp + .c source together. PerfBrains fuses all three, applying strict precedence rules so authoritative .lrp correlation rules always win over heuristic detection.

Correlation engine

Detects JSONPath, boundary, regex, and response-header extractors. Cross-VU diff analysis identifies which values change between users. Every extractor carries a confidence score.

Replay validation

Run the converted script against a mock server seeded from the original recording. A 96% validation score means your correlations are firing correctly — before you ever touch staging.

Fidelity scoring

HIGH / MEDIUM / LOW fidelity rating tells you immediately how complete the correlation detection is. Upload .lrp + 2 VUs for HIGH fidelity — the difference is measurable.

CI/CD integration

REST API with API key auth. Poll for completion. Download the ZIP. Trigger validation. The whole flow works in a shell script, GitHub Action, or Jenkins pipeline.

Enterprise ready

Multi-tenancy, OIDC/SSO, audit log, webhooks, rate limiting, and data retention policies. On-premise Docker Compose or Helm chart. Deployable in air-gapped environments.

Every major format,
covered

From LoadRunner 12 through 2023, NeoLoad ZIP archives and YAML, browser HAR captures — to all five modern target frameworks.

Source formats

LR
LoadRunner 12.x
.log + .lrp + .c source
LR
LoadRunner 2020–2023
Extended log, multi-VU
NL
NeoLoad 6+
.nlp ZIP archive
NL
NeoLoad YAML
neoload.yaml (as code)
HAR
Proxy HAR
Browser dev tools capture

Target frameworks

G
Gatling OSS 3.9+
Scala DSL + feeder CSVs
GE
Gatling Enterprise
Cloud execution + SLA monitoring
JM
Apache JMeter 5.6+
XML .jmx + feeder CSVs
BM
BlazeMeter
JMeter-compatible cloud
AZ
Azure Load Testing
JMeter for Azure DevOps

Prove it works
before you run it

Most migration tools ship output and say "trust us." PerfBrains ships output and then proves it's correct — with an automated replay validation and a PDF report you can share with stakeholders.

Tier 1

Static IR check — instant, zero cost

Parses the output script before execution. Verifies all correlation variables are defined, all extractors have consumers, and no orphan parameters exist. Runs in milliseconds.

Tier 2

Mock replay — no application needed

Seeds a local HTTP server from the original recording. Runs the converted script against it. Detects correlation failures, unmatched requests, and status mismatches — completely offline.

Tier 3

Live replay against your staging or production server

PerfBrains runs the script against your TARGET_HOST and compares live HTTP responses to the recording. For internal apps, install perfbrains-cli inside your network — the agent runs locally and streams results back with no inbound firewall access required.

96%
validation score
✓ PASSED
ModeMock (offline)
Total requests247
Matched238 ✓
Dynamic field diffs9 (expected)
Extractors fired14 / 14 ✓
Auth failures (401)0 ✓
Duration38.4s
80–90%
reduction in script migration time
5 targets
Gatling, JMeter, BlazeMeter & more
96%
average mock validation score
3 models
SaaS, on-premise, dedicated cloud

Real output, not stubs

PerfBrains generates idiomatic, production-ready code — not a skeleton that needs days of manual work to make runnable.

LoadRunner Action.c (source)
// VuGen Action.c — checkout flow
Action()
{
  web_add_cookie("JSESSIONID={JSESSIONID}");
  
  lr_start_transaction("Login");
  web_submit_data("login",
    "Action=https://{HOST}/api/auth",
    "EncType=application/json",
    ITEMDATA,
    "Name=username",
    "Value={username}",
    ENDITEM,
    LAST);
  lr_end_transaction("Login", LR_AUTO);
  
  web_reg_save_param("auth_token",
    "LB=token\":",
    "RB=\",",
    LAST);
}
Gatling OSS CheckoutFlowSimulation.scala
class CheckoutFlowSimulation extends Simulation {

  val httpProtocol = http
    .baseUrl(sys.env.getOrElse("TARGET_HOST", ""))
    .acceptHeader("application/json")
    .disableCaching

  val users = csv("users.csv").circular

  val login = group("Login") {
    exec(http("POST /api/auth")
      .post("/api/auth")
      .body(StringBody("""{"username":"${username}"}"""))
      .check(jsonPath("$.data.token")
        .saveAs("auth_token")))    // ← extracted
    .pause(1200.milliseconds)
  }
}
01

30-minute technical demo

We convert one of your actual LoadRunner or NeoLoad scripts live on the call — no canned demo, no slide deck. You see the exact output PerfBrains produces for your codebase before you make any commitment.

→ No commitment required
02

Proof of concept migration

We run a full POC on a representative sample of your scripts — typically 3 to 5. You receive the converted output, validation reports, and a fidelity summary you can share with your engineering leadership.

→ Usually 5–10 business days
03

Custom agreement on scope & price

Pricing is agreed based on your migration scope — number of scripts, deployment model (SaaS or on-premise), and support level required. No per-seat tiers. No surprise overages. One clear statement of work.

→ Fixed-scope or retainer options
80–90%
reduction in engineering hours spent on script migration
2–5 days
saved per script compared to manual migration by a senior engineer
96%
average mock validation score on first conversion run

Start with a demo on your own scripts

Bring a LoadRunner or NeoLoad script to the call. We'll convert it live, walk through the validation report, and answer every technical question your team has.

Performance engineering
insights

Migration guides, framework comparisons, and practical tutorials from the PerfBrains team.

CLIENT STORY CASE STUDY
Customer Story·April 2026·10 min read

From 94 LoadRunner Scripts to Gatling in Six Weeks: How Meridian Financial Escaped a $380K Licence Renewal

Meridian's performance team faced an impossible deadline: migrate a decade of LoadRunner scripts before their licence expired. Here's how they found PerfBrains, ran a POC in a week, and converted their entire test suite — with a 97% validation score on first run.

Read story
LR → GATLING
Migration Guide·March 2026·12 min read

How to Migrate from LoadRunner to Gatling: A Complete 2026 Guide

Everything you need to know about migrating LoadRunner scripts to Gatling OSS — from extended log recording to correlation extraction, feeder CSV generation, and running your first load test.

Read guide
NL → JMETER
Migration Guide·February 2026·10 min read

NeoLoad to JMeter Migration: Everything You Need to Know in 2026

A practical guide to converting NeoLoad user paths, extractors, and load models to JMeter .jmx format — with step-by-step instructions for handling conditions, loops, and SLA thresholds.

Read guide
G vs JM
Framework Comparison·January 2026·8 min read

Gatling vs JMeter in 2026: Which Performance Testing Framework Should You Choose?

An objective comparison of Gatling and JMeter for modern performance engineering teams — covering scripting model, CI/CD integration, reporting, cloud execution, and total cost of ownership.

Read article

Ready to see it
on your scripts?

Start with a live demo on your actual scripts. No slides. No canned walkthrough. Just PerfBrains converting your LoadRunner or NeoLoad scripts so you can evaluate the output yourself.

See a real migration
in 30 minutes

We'll take your actual LoadRunner or NeoLoad scripts and convert them live, so you see exactly what PerfBrains produces for your codebase.

Live conversion on your scripts

Not a canned demo. We use your files so you can validate the output immediately.

Full validation report

We run the Tier-2 mock validation live and walk through the score, extractor results, and any coverage warnings.

On-premise options covered

If you're in a regulated environment, we'll show the Docker Compose and Helm deployment paths.

30 minutes, no pressure

No sales deck. We answer technical questions and you walk away with the output files.

Book a 30-min demo
Usually responds within one business day.

Demo request received

We'll reach out to within one business day to confirm a time.

In the meantime, you can learn more about how we scope engagements at our get started section.

Back to blog

How to Migrate from LoadRunner to Gatling: A Complete 2026 Guide

Migrating from LoadRunner to Gatling is one of the most common performance engineering projects in 2026 — and one of the most underestimated. This guide covers everything: what makes the migration hard, what you need to get right, and how to validate the output before your first load test.

Why migrate from LoadRunner to Gatling?

LoadRunner has been the enterprise performance testing standard for over two decades. But the economics have shifted dramatically. LoadRunner perpetual licences cost tens of thousands per seat. Maintenance agreements are substantial. And the toolchain doesn't integrate naturally with modern CI/CD pipelines — it was built for a world where performance testing happened after development, not inside it.

Gatling OSS, by contrast, is free. It integrates natively with Maven and Gradle. Its Scala DSL produces human-readable scripts that can be code-reviewed, version-controlled, and maintained like any other codebase. And its reporting is excellent.

The business case for migration is clear. The technical challenge is the hard part.

What makes LoadRunner to Gatling migration difficult

The core challenge isn't the HTTP requests themselves — those are straightforward. The challenge is correlations.

LoadRunner uses a proprietary correlation mechanism: the .lrp project file contains web_reg_save_param rules that capture dynamic values (session tokens, CSRF tokens, cart IDs) from HTTP responses and inject them into subsequent requests. Translating these rules into Gatling's .check(jsonPath(...).saveAs(...)) or .check(bodyString.transform(...).saveAs(...)) is not mechanical — it requires understanding what each parameter does and where it appears in the request sequence.

With a 250-request script and 14 correlation rules, doing this manually takes two to five days for an experienced engineer. Getting one rule wrong means a 401 on the first test run — often not caught until you're already in the load lab.

Step 1: Record with Extended log — and use multiple VUs

The single most important thing you can do before attempting a migration is ensure your LoadRunner recording captures the right data. PerfBrains (and any migration tool) can only work with what's in the log.

Required: Extended log level. In VuGen, go to Run-time Settings → Log → Logging Options → Extended log. Check all three sub-options: Data returned by server, Request/response headers, and Advanced trace.

Extended log is essential because correlation detection requires the full HTTP response body. Basic and Standard log levels omit response bodies, making it impossible to detect where dynamic values are served from.

Equally important: record with at least two virtual users. Cross-VU diff analysis — comparing which values differ between User 1's recording and User 2's recording — is the most reliable way to identify dynamic values that need correlation. A value that is SESSION_VU1_TOKEN for one user and SESSION_VU2_TOKEN for another is obviously dynamic. A value that is the same for both users is likely a static application constant that doesn't need correlation.

Step 2: Export the .lrp project file

The .lrp file (LoadRunner project XML) is your gold mine. It contains:

Export it from VuGen: File → Save As → Save .lrp. Upload it alongside the log file when converting.

Step 3: Convert and verify fidelity

Using PerfBrains, a typical conversion looks like this:

perfbrains convert \ --source checkout_flow_extended.log \ --lrp CheckoutFlow.lrp \ --source-c Action.c \ --target gatling_oss \ --name checkout-flow-v2

After conversion, check the fidelity rating. HIGH fidelity means all three inputs were present and at least two VU threads were detected — this is what you want. MEDIUM fidelity means either the .lrp was missing or only one VU was recorded. The conversion still works, but extractors are inferred rather than derived from authoritative rules.

Step 4: Review the correlation report

The correlation report is the most important QA step. Open the job detail page and expand the correlation report. For each extractor, you'll see:

Focus on MEDIUM and LOW confidence extractors. These were inferred by heuristic analysis rather than derived from your .lrp rules. Review the extraction expression in the output Scala file and verify it matches what you'd expect.

Step 5: Run mock validation before touching staging

Before you point the converted script at a real application, run the Tier-2 mock validation. This executes the Gatling simulation against a local HTTP server seeded from your original LoadRunner recording — no real application required.

A validation score above 85% means your correlations are firing correctly. A score below 85% tells you a correlation is broken before you waste time on a staging run.

Common cause of validation failure: a boundary extractor whose left boundary contains HTML that varies between requests. If the mock validation shows requests with replayed_status=404, check those requests in the diff report — the path will contain literal ID strings instead of variable references.

Step 6: Run on staging and set TARGET_HOST

PerfBrains never hardcodes the target hostname in the output. Instead, the Gatling simulation reads it from an environment variable:

val httpProtocol = http .baseUrl(sys.env.getOrElse("TARGET_HOST", "")) # Set before running: export TARGET_HOST=https://staging.your-app.com mvn gatling:test -Dgatling.simulationClass=CheckoutFlowSimulation

This separation is intentional: the same script can run against dev, staging, and production without modification — just change the environment variable.

Common LoadRunner to Gatling gotchas

LoadRunner patternGatling equivalentNotes
web_reg_save_param boundary.check(bodyString.transform(...)) or regexPerfBrains generates this automatically from .lrp rules
lr_think_time().pause(N.milliseconds)Scaled by .lrp think time policy factor
lr_start_transaction / lr_end_transactiongroup("TransactionName")Mapped directly — no changes needed
Parameter files (.dat)Feeder CSVsGenerated automatically from .lrp parameter definitions
Cookie handling (manual)Automatic via httpProtocolGatling manages cookies automatically — remove manual cookie code

Summary

The LoadRunner to Gatling migration is technically achievable, but doing it manually is slow, error-prone, and expensive. The keys to a successful migration are: recording with Extended log and multiple VUs, preserving the .lrp correlation rules, verifying with mock replay before touching staging, and reviewing MEDIUM confidence extractors carefully.

PerfBrains automates the mechanical work — parsing, fusion, correlation detection, and emission. What remains is the engineering judgment: deciding which MEDIUM confidence extractors to trust, verifying the load model matches your intended test design, and confirming the output against your original business requirements.

Back to blog

NeoLoad to JMeter Migration: Everything You Need to Know in 2026

NeoLoad's proprietary project format and protocol-level abstraction make migration to JMeter non-trivial. This guide walks through the structural differences, the traps to avoid, and how to get a production-ready .jmx file from your .nlp archive.

Why teams are migrating from NeoLoad to JMeter

NeoLoad is a capable tool, but it's expensive, and its ecosystem is narrower than JMeter's. JMeter is open-source, integrates with every major CI/CD platform, has a vast plugin ecosystem, and runs everywhere. BlazeMeter and Azure Load Testing both accept JMeter .jmx files natively, making it the de-facto standard for cloud load execution.

The migration decision is often driven by one of three forces: licence cost reduction, CI/CD integration requirements, or a shift to cloud-based load execution on platforms that don't support NeoLoad natively.

Understanding the NeoLoad project structure

NeoLoad stores its projects as .nlp files — ZIP archives containing multiple XML files. The key components are:

The structural mismatch between NeoLoad and JMeter

NeoLoad and JMeter use fundamentally different concurrency models. NeoLoad uses a population-based model where you define populations and assign user paths to them. JMeter uses thread groups where each thread group directly defines a concurrency level.

More practically, NeoLoad's extractor mechanism is tightly integrated with the user path XML — each request element can have multiple inline extractors. In JMeter, extractors (Post Processors) are child elements of HTTP Sampler elements. The structure is similar but not identical, and the extraction expression syntax differs.

NeoLoad conceptJMeter equivalent
User pathThread Group + controllers
Variable extractor (JSONPath)JSON Extractor (Post Processor)
Variable extractor (regexp)Regular Expression Extractor
Variable extractor (boundary)Regular Expression Extractor (with boundary pattern)
File variableCSV Data Set Config
TransactionTransaction Controller
If / else conditionIf Controller (with __jexl3 condition)
While loopWhile Controller
SLA thresholdResponse Assertion + Duration Assertion
Init sectionsetUp Thread Group
End sectiontearDown Thread Group

Step 1: Export your .nlp archive

In NeoLoad, export the project as an .nlp file: File → Save As → .nlp format. The .nlp archive contains everything — user paths, extractors, parameters, load model, and SLAs. Unlike LoadRunner, you don't need a separate project file alongside the log.

If you're using NeoLoad as code, export your neoload.yaml. PerfBrains supports both formats and produces identical output from either.

Step 2: Understand what will and won't convert automatically

Converts fully automatically: HTTP/HTTPS requests, JSONPath and regex extractors, file parameters → CSV Data Sets, transactions, init/end sections, think times, response assertions.

Converts with caveats: Conditions (if/else) map to JMeter If Controllers, but NeoLoad's condition expressions use a different syntax than JMeter's __jexl3. PerfBrains generates the correct structure, but you should review the condition expressions in the output .jmx.

Not converted in v1.0: Non-HTTP protocols (WebSocket, gRPC), custom NeoLoad plugins, NeoLoad Cloud execution profiles.

Step 3: Convert with PerfBrains

perfbrains convert \ --source checkout_flow.nlp \ --target jmeter \ --name checkout-flow-jmeter

The output is a .jmx file and one or more feeder .csv files. You can open the .jmx directly in JMeter's GUI for inspection, or run it headlessly from the command line.

Step 4: Verify extractor expressions

NeoLoad's JSONPath expressions use the same syntax as JMeter's JSON Extractor — this is a clean mapping. Regex extractors also map cleanly. The one to watch is boundary extractors: NeoLoad stores them as separate left-boundary and right-boundary strings, while JMeter's Regular Expression Extractor requires these to be combined into a single regex pattern. PerfBrains generates (leftBoundary)(.*?)(rightBoundary) — verify this makes sense for each extracted value.

Step 5: Run mock validation and review the diff

The Tier-2 mock validation is particularly valuable for NeoLoad to JMeter migrations because it will immediately surface any extractor expression issues. A failed extraction typically shows up as either a 4xx on the next request (wrong parameter value) or a 500 (parameter is null).

Run the mock validation, download the diff report, and filter to Failed requests. For each failure, find the corresponding extractor in the correlation report and verify the expression.

Running your converted JMeter script

# Set target host (protocol goes to JMeter separately) export TARGET_HOST=your-staging-app.com # Run headlessly jmeter -n \ -t CheckoutFlow.jmx \ -Jhost=$TARGET_HOST \ -Jprotocol=https \ -Jthreads=10 \ -Jloops=1 \ -l results.jtl \ -e -o report/

NeoLoad to JMeter: common issues and fixes

Back to blog

Gatling vs JMeter in 2026: Which Performance Testing Framework Should You Choose?

Both Gatling and JMeter are excellent, mature performance testing tools — but they have very different design philosophies, strengths, and weaknesses. This comparison will help you decide which one belongs in your pipeline.

The short answer

Choose Gatling if your team is developer-focused, already working in a JVM/Scala ecosystem, values code-as-tests over GUI configuration, and wants excellent built-in HTML reporting with minimal setup.

Choose JMeter if you need the broadest protocol support, have existing JMeter scripts or expertise, want a GUI for non-technical stakeholders to write tests, or need to run on BlazeMeter, Azure Load Testing, or other cloud platforms that have first-class JMeter support.

Choose both if you're doing a migration project — PerfBrains can convert your scripts to either format, so you're not locked in.

Architecture and concurrency model

This is the most important technical difference. JMeter is thread-based: each virtual user is an OS thread. This limits practical concurrency — most systems top out around 1,000–2,000 threads before memory and context-switching overhead becomes prohibitive. JMeter distributed testing (controller + injectors) is the standard workaround, but it adds operational complexity.

Gatling is built on Akka actors and Netty NIO. Each virtual user is a lightweight actor, not a thread. A single Gatling process can sustain tens of thousands of concurrent users with modest hardware. This makes Gatling significantly more resource-efficient for high-concurrency scenarios.

For a realistic scenario — 1,000 concurrent users, 5-minute ramp, 300-request scripts — Gatling typically uses 30–50% less CPU and 60–70% less memory than JMeter. The difference becomes more pronounced above 2,000 users.

Scripting model

DimensionGatlingJMeter
Script formatScala DSL (code)XML .jmx (GUI or code)
Learning curveSteeper — requires Scala knowledgeShallower — GUI-driven
Code readabilityExcellent — DSL reads naturallyLow — XML is verbose and hard to diff
Version controlNatural — Scala files diff cleanlyPainful — XML diffs are noisy
IDE supportFull IntelliJ/VS Code support with completionLimited for .jmx files
ParameterisationFeeder CSV or custom feeder objectsCSV Data Set Config or __csvRead
CorrelationjsonPath(...).saveAs(...)JSON Extractor / Regex Extractor

Protocol support

JMeter wins decisively on protocol breadth. Beyond HTTP/HTTPS, JMeter supports JDBC, JMS, FTP, SMTP, LDAP, WebSocket (via plugin), gRPC (via plugin), MongoDB (via plugin), and more. If you're testing anything other than HTTP APIs, JMeter is almost certainly the right choice.

Gatling's protocol support is narrower: HTTP/HTTPS, WebSocket (built-in), JMS (Enterprise only), and gRPC (Enterprise only). For pure web API testing, this is rarely a limitation. For enterprise integration testing involving queues, databases, or legacy protocols, JMeter is the practical choice.

Reporting and observability

Gatling generates beautiful, interactive HTML reports out of the box. The reports include response time distribution, percentile curves, throughput over time, and request-level breakdown. No setup required — they're generated from the simulation.log automatically.

JMeter generates JTL (CSV or XML) results files. The built-in HTML dashboard reporter is functional but less polished than Gatling's. Most teams pair JMeter with Grafana + InfluxDB for real-time metrics, which is more powerful but requires more setup.

CI/CD integration

Both tools integrate well with CI/CD pipelines, but the experience differs:

Cloud load testing

JMeter has broader cloud support by a significant margin. BlazeMeter accepts JMX files natively. Azure Load Testing runs JMeter scripts directly. AWS Distributed Load Testing uses JMeter. OctoPerf supports JMeter.

Gatling's cloud story runs through Gatling Enterprise (formerly Gatling Frontline) — the commercial product that adds distributed execution, Teams/organisation management, and advanced reporting. Gatling Enterprise is excellent, but it's a separate paid product.

Total cost of ownership

Cost factorGatling OSSJMeterGatling Enterprise
LicenceFree (Apache 2.0)Free (Apache 2.0)Commercial (contact)
Cloud executionSelf-managed or EnterpriseBlazeMeter, Azure LT, etc.Included
ReportingBuilt-in HTMLGrafana stack or JMeter reportsAdvanced dashboards
Infra cost per testLower (Akka concurrency)Higher (thread-per-VU)Lower
Script maintenanceLow (code, version control)Medium (XML, GUI dependency)Low

Our recommendation for 2026

For teams building modern, developer-owned performance testing practices integrated into CI/CD, Gatling OSS is the better long-term choice. The code-first approach, excellent reporting, and lower infrastructure footprint make it the right foundation for a DevOps performance testing culture.

For teams with existing JMeter investments, protocols beyond HTTP, or a requirement for BlazeMeter/Azure Load Testing, JMeter remains the pragmatic choice. Don't migrate away from something that's working just to be on trend.

The good news: if you're migrating from LoadRunner or NeoLoad, PerfBrains converts to both. You don't have to decide upfront — convert to both formats, evaluate the output, and choose based on your team's actual requirements.

Back to blog

Understanding LoadRunner Correlation Rules: LRP Files Explained

The .lrp project file is the most underrated artefact in a LoadRunner migration. It contains the correlation rules your QA team spent months tuning. Here's exactly what's in it and how to use it.

What is a .lrp file?

The .lrp (LoadRunner Project) file is an XML document — sometimes ZIP-wrapped in newer versions — that VuGen generates alongside your script. It stores everything the GUI configures that doesn't live in the .c source files: correlation rules, think time policy, parameter definitions, pacing, and iteration settings.

Most migration guides tell you to start with the extended log. That's correct. But discarding the .lrp means throwing away the most authoritative correlation data you have.

Anatomy of a correlation rule

Each correlation rule in the .lrp maps to a web_reg_save_param call. In XML it looks like this:

<Rule Name="auth_token"> <LeftBoundary>"token":"</LeftBoundary> <RightBoundary>"</RightBoundary> <Scope>all</Scope> <Instance>first</Instance> </Rule>

The four fields tell you everything you need to produce a Gatling or JMeter extractor: what text appears immediately before the dynamic value, what text appears immediately after, whether to search headers and body or just the body, and which occurrence to capture.

Left and right boundaries → Gatling regex check

A boundary rule translates directly to a Gatling regex check. The left boundary becomes the literal prefix before the capture group, the right boundary becomes the suffix:

// LRP rule: LB = `"token":"`, RB = `"` // Gatling output: .check(regex(""""token":"(.*?)"""").saveAs("auth_token"))

In JMeter the same rule becomes a Regular Expression Extractor with the pattern "token":"(.*?)" and template $1$.

The Scope and Instance fields

Scope controls where LoadRunner searches for the boundary. all means response body and headers. body means body only. headers means response headers only. When converting, scope determines whether to use bodyString or header() in Gatling.

Instance controls which occurrence is captured. first is the default. last means capture the final occurrence in the response. all means capture all occurrences into an array — this is the most complex to convert and typically becomes a findAll in Gatling.

Parameter definitions in .lrp

The Parameters section defines feeder files. Each parameter has a filename, column number, and selection strategy (sequential, random, unique). This maps directly to Gatling's csv("filename.csv").circular feeder declarations. PerfBrains reads these definitions and generates the feeder CSV structure automatically.

Extracting .lrp from an archive

In LR 2020+, the .lrp file is embedded in a ZIP archive. Export it from VuGen via File → Save As → select .lrp format. The resulting file will either be raw XML or a ZIP — PerfBrains handles both. If you're automating the extraction, use unzip -p script.lrp to pipe the XML to stdout.

Back to blog

Performance Testing in CI/CD: A Practical Guide for 2026

Most teams run load tests manually, weeks after code ships. This guide shows how to run performance tests on every pull request, with SLA gates that automatically block deployments when response times regress.

Why shift-left performance testing is hard

The main obstacle isn't tooling — it's that full load tests take too long and require too much infrastructure to run on every commit. The solution is a tiered approach: a lightweight smoke load test on every PR, a full regression test nightly, and a capacity test before major releases.

GitHub Actions with Gatling

name: Performance smoke test on: [pull_request] jobs: perf: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: { java-version: '21', distribution: 'temurin' } - name: Run Gatling smoke test run: | mvn gatling:test \ -Dgatling.simulationClass=CheckoutFlowSimulation \ -DTARGET_HOST=${{ secrets.STAGING_URL }} \ -Dusers=10 -DrampUp=30 -Dduration=120 - name: Upload report uses: actions/upload-artifact@v4 with: name: gatling-report path: target/gatling/

Setting SLA thresholds that fail the build

In Gatling, add assertions to your simulation's setUp block:

setUp(scn.inject(...)) .protocols(httpProtocol) .assertions( global.responseTime.percentile(95).lt(2000), global.successfulRequests.percent.gte(99), forAll.responseTime.percentile(99).lt(5000) )

If any assertion fails, Gatling exits with code 2, which GitHub Actions treats as a failure and blocks the merge.

JMeter in Azure DevOps

Azure Load Testing has first-class JMeter support. Upload your .jmx file and set pass/fail criteria in the portal or via YAML:

- task: AzureLoadTest@1 inputs: azureSubscription: 'prod-connection' loadTestConfigFile: 'load-test.yaml' resourceGroup: 'perf-rg' loadTestResource: 'perfbrains-lt'

Baseline comparison

The most valuable thing in a CI/CD performance pipeline isn't absolute thresholds — it's regression detection. Store the p95 response time from the last green build and fail if the current run is more than 20% slower. This catches performance regressions that are still within SLA but trending badly.

Back to blog

From Browser HAR to Load Test: Capturing and Converting Proxy Recordings

HAR files are the fastest way to bootstrap a load test when you don't have an existing VuGen or NeoLoad script. A 10-minute browser recording can become a running Gatling simulation in under an hour.

What is a HAR file?

HAR (HTTP Archive) is a JSON format for recording browser network activity. Every request and response — URL, method, headers, body, status, timing — is captured in a single file. Chrome, Firefox, Edge, Charles Proxy, Fiddler, and mitmproxy all export HAR.

Recording a clean HAR in Chrome

  1. Open DevTools (F12) and go to the Network tab
  2. Check "Preserve log" and clear the existing entries
  3. Walk through the user journey you want to load test
  4. Right-click any request → Save all as HAR with content

Tip: Record in an incognito window to avoid cached resources and existing session cookies contaminating the capture. Filter to XHR/Fetch requests before exporting to remove static assets and keep the HAR focused on API calls.

HAR limitations vs VuGen recordings

HAR files record a single browser session — equivalent to a single-VU LoadRunner recording. This means the correlation engine can't use cross-VU diff to identify dynamic values automatically. Instead, PerfBrains uses heuristic analysis: values that look like UUIDs, session tokens, or numeric IDs are flagged as dynamic and get LOW or MEDIUM confidence extractors.

For better correlation detection, record the same flow twice in separate incognito windows and upload both HAR files. PerfBrains' pair mode treats them as VU-1 and VU-2, enabling the same cross-run diff that makes LoadRunner multi-VU recordings so effective.

Converting with PerfBrains

perfbrains convert \ --source capture.har \ --target gatling_oss \ --name checkout-flow

The output includes the Gatling simulation, feeder CSVs for any detected parameters, and a validation report showing which extractors fired correctly against the mock server.

Back to blog

Deploying PerfBrains On-Premise: Docker Compose and Helm Guide

Many performance engineering teams work with proprietary scripts that can't leave the corporate network. PerfBrains' on-premise deployment supports both a simple single-server Docker Compose install and a production Kubernetes deployment via Helm.

When to use on-premise

Use the on-premise deployment when your LoadRunner or NeoLoad scripts contain sensitive application data, PII in request bodies, internal hostnames, or authentication credentials that cannot be uploaded to a SaaS platform. The on-premise version runs entirely inside your network — no script data leaves your infrastructure.

Docker Compose — single server

The fastest path to a running on-premise instance. Requires Docker Desktop or Docker Engine on the target server:

git clone https://github.com/perfbrains/perfbrains cd perfbrains cp .env.example .env # Edit .env: set POSTGRES_PASSWORD, MASTER_API_KEY docker compose -f infra/onprem/docker-compose.onprem.yml up -d docker compose exec api python -m scripts.setup

The setup script creates the database schema, generates an initial admin API key, and prints it to stdout. Store it — it won't be shown again.

Helm — Kubernetes

helm install perfbrains ./infra/helm/perfbrains \ --namespace perfbrains \ --create-namespace \ --set secrets.postgresPassword=YOUR_PG_PASSWORD \ --set secrets.masterApiKey=YOUR_MASTER_KEY \ --set ingress.host=perfbrains.internal \ --set ingress.tls.enabled=true

Air-gapped environments

For networks with no internet access, pre-pull the Docker images on a connected machine and transfer them:

docker pull perfbrains/api:latest docker pull perfbrains/worker:latest docker save perfbrains/api:latest | gzip > api.tar.gz # Transfer api.tar.gz to air-gapped host, then: docker load < api.tar.gz

Storage configuration

By default the on-premise installation stores uploaded scripts and output files on the local filesystem. For multi-server deployments, configure an S3-compatible store (MinIO works well) by setting STORAGE_BACKEND=s3 and the corresponding bucket credentials in your .env file.

Back to blog

Think Times in Load Tests: Replay, Ignore, or Randomise?

Think time is one of the most consequential — and most misunderstood — settings in a load test. Getting it wrong means either under-stressing the system or producing meaningless results.

What think time actually models

Think time represents the time a real user spends reading a page, filling a form, or making a decision between requests. Without think time, virtual users hammer the server as fast as the network allows — which tests raw throughput but doesn't model realistic concurrent load.

Replay as recorded

Use this when you want to model the exact behaviour captured in your recording. LoadRunner's lr_think_time() calls are preserved at face value. Best for: replicating a specific observed transaction rate, compliance testing against a documented user journey.

Downside: a single recording captures one user's pace on one day. If the tester typed slowly during the recording, think times are inflated and your load test underestimates concurrency.

Ignore think time

Sets all think times to zero. Virtual users fire requests as fast as the server responds. Best for: API stress tests where there is no human interaction, finding the raw throughput ceiling, saturation testing.

Do not use this mode when simulating realistic browser-based user journeys — the result bears no resemblance to actual user load.

Randomise within bounds

The most realistic option for most user journey tests. Each think time is drawn from a uniform distribution between a minimum and maximum. A recorded think time of 3 seconds with a 0.5–2.0x multiplier produces think times between 1.5 and 6 seconds.

// Gatling — random pause between 1.5s and 4s .pause(1500.milliseconds, 4.seconds)

In PerfBrains, the think time policy from your .lrp file is applied automatically. If your .lrp specifies random mode with min 1000ms / max 5000ms, every converted script respects those bounds.

The multiplier approach

A practical compromise: replay the recorded think times but apply a multiplier. A 0.5x multiplier doubles the effective load without eliminating think time entirely. LoadRunner's Factor field in the ThinkTime XML element controls this, and PerfBrains maps it to Gatling's pause scaling.

Back to blog

NeoLoad as Code: Migrating YAML Definitions to Gatling Scala DSL

NeoLoad's YAML format was a significant step toward treating load tests as code. Migrating to Gatling's Scala DSL takes that further — version-controlled, IDE-supported, and reviewable in pull requests.

The NeoLoad YAML structure

A neoload.yaml file has five main sections: servers (base URLs), user_paths (the test flows), variables (extractors and parameters), populations (load model), and sla_profiles (pass/fail thresholds). Each maps to a Gatling equivalent.

User paths → Simulation scenarios

Each NeoLoad user path becomes a Gatling scenario(). The init, actions, and end sections map to exec() chains, with init and end running once via Gatling's before and after blocks.

Variable extractors → Gatling checks

NeoLoad YAML typeGatling equivalent
jsonpath.check(jsonPath("$.x").saveAs("var"))
regexp.check(regex("""pattern""").saveAs("var"))
boundary.check(regex("""lb(.*?)rb""").saveAs("var"))
header.check(header("X-Name").saveAs("var"))
xpath.check(xpath("//path").saveAs("var"))

The population model mismatch

NeoLoad populations use a percentage-based distribution across user paths. Gatling uses injection profiles per scenario. The conversion is straightforward for simple cases: a population with 100 users and a 60s ramp becomes rampUsers(100).during(60.seconds).

For multiple populations, PerfBrains creates one Gatling scenario per user path and combines them in a single setUp() call, scaling user counts by the population percentage.

SLA profiles → Gatling assertions

// NeoLoad SLA: p95 < 2000ms, error rate < 1% // Gatling equivalent: setUp(...) .assertions( global.responseTime.percentile(95).lt(2000), global.failedRequests.percent.lt(1) )
Back to blog

The Real Cost of Manual Script Migration: A Performance Team ROI Calculator

When a new CTO asks why the performance team needs budget for tooling, "it saves time" isn't enough. Here's how to build a concrete, defensible ROI model using numbers your finance team will recognise.

The costs most teams don't count

The obvious cost is engineer hours on the migration itself. The less obvious costs are what happens while the migration backlog grows: delayed test cycles, re-scripting bugs found late, and the opportunity cost of experienced engineers doing mechanical work instead of analysis.

A realistic breakdown for a single LoadRunner-to-Gatling migration of a medium-complexity script (250 requests, 14 correlations):

ActivityManual hoursPerfBrains hours
Log parsing + request mapping4–6h~2 min
Correlation rule extraction6–12h~2 min
Think time + feeder setup2–4h~2 min
First test run debugging4–8h0–2h (validation report)
Code review + sign-off2–3h1h
Total18–33 hours1–3 hours

The calculation

At a fully-loaded cost of $120/hour for a senior performance engineer, a single migration costs between $2,160 and $3,960 in labour. A team with 20 scripts to migrate spends $43,000–$79,000 before any other costs. That's before factoring in delayed project timelines when the performance team is the bottleneck.

The multiplier: migration debt

Most teams don't migrate all at once. They migrate scripts as projects need them, which means the backlog grows faster than it shrinks. Each quarter of delay adds more scripts to migrate as development teams ship features. Teams that have been on LoadRunner for 10+ years routinely have 50–200 scripts in the backlog — at $3,000 per script, that's a $150,000–$600,000 liability sitting in a folder.

Building the business case

The most persuasive framing for finance: this is not a tooling purchase, it's a debt elimination programme. Present the migration backlog as technical debt with a known dollar value, show the quarterly cost of not converting (delayed test cycles, blocked releases), and position PerfBrains as the amortisation schedule.

A typical POC with 5 scripts takes one sprint. The output is a validation report showing exactly what was converted and what the mock replay score was — concrete evidence to present to stakeholders before committing to a full migration programme.

Back to blog

Why Open Source Load Testing Tools Are Now Enterprise-Ready

Five years ago, recommending Gatling or JMeter over LoadRunner in a Fortune 500 environment would have been a hard sell. Today it's the default recommendation. Here's what changed.

The objections that used to stick

Enterprise teams historically had three objections to open source load testing tools: lack of support SLAs, missing protocol coverage for legacy systems, and the expertise gap — LoadRunner had GUI-based recording that didn't require developers to write test code. All three objections have eroded significantly.

Support is no longer a differentiator

Gatling offers commercial support through Gatling Enterprise with defined SLAs. JMeter has a mature ecosystem of commercial support providers. More practically, both tools have vastly larger community ecosystems than LoadRunner — Stack Overflow answers for Gatling Scala DSL questions are faster, more accurate, and more numerous than for VuGen C scripting.

Protocol coverage has converged for 90% of use cases

The protocols that matter for modern web application testing — HTTP/1.1, HTTP/2, WebSocket, gRPC — are well-supported in both Gatling and JMeter. LoadRunner's advantage lies in legacy enterprise protocols: SAP GUI, Citrix, RDP, JDBC. If your system doesn't need those, the protocol argument doesn't hold.

Code-first is now a strength, not a weakness

The GUI recording argument has inverted. In 2025, performance testing is shifting left — it belongs in the development pipeline, not as a post-release gate. Scripts need to be code-reviewed, versioned, and maintained alongside application code. A Gatling Scala simulation in a Maven project fits that model. A VuGen .c file attached to a binary .lrp archive does not.

Teams that move to Gatling consistently report that developer adoption improves once performance tests look like regular code. The barrier to contributing shifts from "I need LoadRunner training" to "I can read this Scala."

Total cost of ownership over 5 years

LoadRunner perpetual licences for a team of 5 performance engineers, with maintenance, cost roughly $150,000–$250,000 over five years depending on negotiated terms. Gatling OSS is free. Gatling Enterprise for the same team scales based on usage. JMeter is Apache-licensed with zero licence cost. The savings compound: every year you're not renewing a LoadRunner maintenance agreement is money that can go to headcount, infrastructure, or training.

Back to blog

Keeping Test Scripts Inside Your Perimeter: A Security Guide for Performance Teams

A LoadRunner extended log from a checkout flow contains real hostnames, session token patterns, authentication endpoints, and sometimes production-like user data. Uploading that to an external SaaS platform is a security conversation your team needs to have before the CISO has it for you.

What's actually in a performance test script

Most engineers think of a load test script as synthetic traffic. In practice, a LoadRunner extended log recording contains:

For teams in regulated industries — finance, healthcare, defence — uploading this data to any external service is a compliance event, not just a risk consideration.

The on-premise conversion model

PerfBrains' on-premise deployment runs entirely inside your network. Scripts are uploaded to your own storage (local filesystem or your own S3 bucket), processed by workers running on your own infrastructure, and outputs are stored in your own database. Zero script data reaches PerfBrains' servers.

The on-premise model also means the conversion pipeline is auditable — your security team can inspect exactly what runs against the scripts, which is not possible with any cloud-based conversion service.

Open source toolchain — no black boxes

Running Gatling or JMeter on-premise means your converted scripts execute on infrastructure you control, against systems you own, with no third-party involvement in the traffic flow. Compare that to cloud-based load testing platforms where test traffic routes through external load injector infrastructure — a model that is incompatible with many internal application environments and explicitly forbidden by some security policies.

Data sanitisation before migration

Even with on-premise deployment, good hygiene before migration is worth the effort. Before uploading scripts to any system:

PerfBrains' dependency validator will flag scripts that appear to contain literal credential patterns, but no automated check replaces a manual review for sensitive data.

Compliance considerations

For teams subject to SOC 2, ISO 27001, PCI-DSS, or HIPAA controls, the on-premise deployment model is typically the only one that satisfies the data residency and access control requirements for test artefacts. PerfBrains' on-premise deployment supports OIDC/SSO integration, audit logging of all conversions, and configurable data retention policies — all features that appear on compliance questionnaires.

Back to blog

Escaping Vendor Lock-In: The Case for Tool-Agnostic Performance Testing

OpenText acquired Micro Focus in 2023, which owned LoadRunner. NeoLoad was acquired by Tricentis. Both acquisitions were followed by pricing changes that surprised existing customers. This is not unusual — it's the normal lifecycle of enterprise software tools. The question is whether your test suite is portable when it happens.

What vendor lock-in looks like in practice

Performance test lock-in has three layers. The first is the script format — VuGen .c files and .lrp projects are proprietary formats that only LoadRunner can execute. The second is the execution infrastructure — LoadRunner Controller and Load Generator licences are required to run the scripts at scale. The third and most expensive layer is the institutional knowledge — engineers who have spent years learning VuGen quirks and correlation debugging techniques specific to one tool.

Each layer is a switching cost. Companies that have been on LoadRunner for 10 years often have all three layers stacked: hundreds of proprietary scripts, infrastructure dependencies, and a team whose expertise is non-transferable to any other tool.

The acquisition risk is real and recent

The LoadRunner and NeoLoad acquisitions are recent examples, but the pattern goes back decades. Compuware APM, Mercury LoadRunner (before HP), Segue SilkPerformer — every commercial performance testing tool has changed hands at least once, and each transition brought pricing restructuring and eventually product discontinuation or marginalisation.

Open source tools do not have acquisition risk. Apache cannot be acquired. The Gatling codebase is on GitHub under an Apache 2.0 licence. In the worst case — which is extremely unlikely — you fork it.

Portability as an engineering principle

The migration to Gatling or JMeter is not just a cost-saving exercise. It's an architectural decision to store your performance test suite in a format that your team owns, can read, can version-control, and can run without a vendor relationship. Gatling Scala DSL is readable code. JMeter XML, while verbose, is an open format with excellent tooling support.

A performance test suite in open-format scripts is an asset. A performance test suite locked to a proprietary tool is a liability — it depreciates the moment the vendor's pricing model changes.

The conversion window

The best time to migrate is when you have time to do it properly — not when a contract renewal forces your hand. Teams that migrate proactively can run both environments in parallel, validate converted scripts against originals, and phase the migration across quarters. Teams that migrate under price pressure do it in a scramble, which is where quality gets compromised.

PerfBrains exists to make the proactive migration fast enough that there's no reason to delay it.

Back to blog

How PerfBrains Validates Converted Scripts Before You Run a Single Load Test

Most script migration tools give you output and say "good luck." PerfBrains gives you output and then proves it works — with a mock replay that executes the converted script against a local server seeded from your original recording, before you ever connect to a real application.

Why validation matters more than conversion speed

The most expensive part of a failed migration isn't the time spent converting the script — it's discovering the correlation is wrong at load test time. A single broken correlation means 401 errors cascading through every subsequent request, a test run that produces meaningless results, and an afternoon of debugging to find the one extractor that stopped firing.

PerfBrains' validation system is designed to catch that before it happens. The validation score you see on every conversion report tells you exactly how many extractors fired, how many requests matched, and which specific requests failed — before you run anything against a real environment.

Tier 1: Static validation (instant, always runs)

The first pass checks the converted IR (Intermediate Representation) for structural completeness: every request has a URL and method, every correlation annotation has an extractor spec, and the script compiles. This catches malformed inputs, unsupported protocol types, and configuration errors within seconds of upload.

Tier 2: Mock replay (offline, default)

The main validation tier. PerfBrains starts an in-process HTTP server seeded from your original recording. The server has pre-loaded responses for every request in your log — exact status codes, headers, and response bodies. The converted script is then executed against this mock server as a real single-VU run.

What the mock validation catches:

The mock server uses a four-level matching strategy: exact path match → path without query string → path prefix → method-only fallback. This means converted scripts that inject variable values into query strings still get valid responses, even when the exact URL differs from the recording.

Understanding your validation score

The score is not just passed/total. It applies penalties for failures and bonuses for successful extractor firings:

A score above 85% means the conversion is ready for staging. A score below 70% tells you there are correlation issues that need attention before the script will produce valid load test results.

Tier 3: Live agent validation

For teams that want to verify against the real application before running at load, the CLI agent (perfbrains-cli) runs the converted script against your actual staging environment and streams results back. This validates not just correlation logic but also response content, which can drift between the original recording and the current application.

Back to blog

From Performance Specialists to Performance Engineers: The Tooling Shift That Changes Everything

The job title "performance tester" is quietly being replaced by "performance engineer." The change is not cosmetic — it reflects a fundamental shift in how performance testing fits into the software delivery lifecycle, and the tooling change is what makes it possible.

What the old model looked like

In the traditional model, performance testing was a specialised function staffed by engineers with deep knowledge of a specific tool — LoadRunner or NeoLoad. These engineers sat in a QA centre of excellence, received scripts from development teams, and ran load tests as a gate before major releases. The cycle time was weeks. The feedback loop was slow. And when a performance issue was found, it was often too late in the cycle to fix affordably.

The tooling was part of what enforced this model. LoadRunner's VuGen required training and a licence. The scripts were in a proprietary format that developers couldn't easily read or modify. The performance team had a monopoly on the toolchain, which meant they had a monopoly on performance knowledge.

What the new model looks like

In the new model, performance tests are written in the same language as application code — Scala, Java, or Kotlin for Gatling; Java or Groovy for JMeter. They live in the same repository as the application. They run in the same CI/CD pipeline. Any developer on the team can read them, modify them, and debug failures.

The performance engineer's role shifts from "person who runs load tests" to "person who designs the test strategy, owns the thresholds, and investigates regressions." It's a higher-value role, and it scales better — one performance engineer can support five development teams instead of being a bottleneck for one.

The migration as the catalyst

Migrating from LoadRunner to Gatling is often the moment this transition happens. The act of converting scripts forces a review of what each test is actually measuring, what the pass/fail criteria should be, and how tests should be structured in the new codebase. Teams that go through this process thoughtfully — rather than doing a mechanical conversion and calling it done — come out the other side with a test suite that the whole engineering organisation can engage with.

The best migrations we've seen treat the conversion as an opportunity to delete scripts that are no longer testing anything relevant, consolidate duplicates, and document the business scenarios each test represents. The output isn't just a format change — it's a cleaner, better-understood test suite.

Hiring changes too

When your performance test suite is Gatling Scala, you can hire from the much larger pool of developers who know JVM languages. You're no longer dependent on finding candidates with specific LoadRunner training. The knowledge is more transferable, the onboarding is faster, and the institutional risk of a key person departure is lower.

This is the underappreciated long-term benefit of the open source migration: it makes the team more resilient, more collaborative, and less dependent on any single tool or any single person.

Back to blog

From 94 LoadRunner Scripts to Gatling in Six Weeks: How Meridian Financial Escaped a $380K Licence Renewal

When Meridian Financial's performance engineering team learned their LoadRunner licence renewal would cost $380,000 — and deliver nothing new — they had six months to migrate a decade's worth of scripts or pay up. This is the story of how they found PerfBrains, ran a proof of concept in one week, and converted their entire estate in six.

The renewal that changed everything

Priya Nair had been Meridian Financial's lead performance engineer for four years. Her team of three owned the performance test suite for Meridian's retail banking platform — 94 LoadRunner scripts covering everything from account login and fund transfers to mortgage application flows and batch processing jobs. The suite had been built up over a decade. It worked. It was tuned. The correlation rules alone represented months of engineering effort.

Then the procurement email arrived. LoadRunner licence renewal: $382,000 for three years, due in six months.

"We'd been talking about migrating to Gatling for two years," Priya says. "The cost was always the argument for staying. At $380K, it became the argument for leaving."

The director of engineering agreed. The instruction was clear: evaluate alternatives, make a recommendation, and have a migration plan on the table within 30 days. If the plan was credible, the renewal would not be signed.

The research phase: what Priya's team evaluated

Priya started where most engineers start: Google and GitHub. She knew Gatling and JMeter well enough to know that the target frameworks weren't the problem. Gatling's Scala DSL was clean, CI/CD-friendly, and well-documented. The performance team already used Gradle. Gatling OSS was a natural fit.

The problem was the migration itself. She pulled up one of their simpler scripts — a 47-request login-and-dashboard flow — and started working through it manually. Four hours later she had translated about a third of the requests. She hadn't touched the correlation rules yet.

"I did the maths. We have 94 scripts. Average complexity is maybe 120 requests. We have three engineers. At this rate, we're looking at four to six months of full-time migration work — and we still have a live release schedule to support. It's not feasible."

She searched for migration tools. She found a handful of open-source converters on GitHub, tried two of them, and got partial output — stubs with no correlation logic, no think times, no feeder CSVs. The output needed as much work as a manual migration. She posted in a performance engineering Slack community asking if anyone had experience with LoadRunner-to-Gatling tooling at scale.

Three responses mentioned PerfBrains.

First contact: the demo request

Priya landed on perfbrains.io on a Tuesday afternoon. She read the feature page, skimmed the validation section, and spent ten minutes on the code compare — specifically the before/after showing web_reg_save_param boundary rules converted to Gatling .check() extractors. That was the part she'd been dreading most.

"The code compare was what got me. It wasn't showing me a stub. It was showing me actual extraction logic. That's the hard part."

She filled in the demo request form — name, company, tool (LoadRunner 2020–2023), number of scripts (51–100), and a note in the message field: "We have 94 scripts, mostly HTTP/HTTPS, some with 15–20 correlation rules each. Renewal deadline in 6 months. Want to see if this is viable for a full estate migration."

She got a response the next morning. A 30-minute slot was booked for Thursday.

The demo: converting Meridian's actual scripts

Priya came to the demo prepared. She'd exported three scripts from LoadRunner in advance — an extended log, the .lrp project file, and the .c source — for their mortgage application flow, which she considered medium complexity: 89 requests, 11 correlation rules, one parameter file with 500 rows of test data.

The PerfBrains team uploaded the files during the call. The conversion ran in under four minutes. The output appeared: a Gatling Scala simulation file, a feeder CSV, and a correlation report showing all 11 extractors with confidence scores.

"Nine were HIGH confidence, two were MEDIUM. The team walked us through each MEDIUM one — explained why the confidence was lower and what to check in the output. That level of transparency was unexpected. I expected a sales pitch. Instead I got a technical walkthrough."

They ran the Tier-2 mock validation live on the call. The validation score came back at 94%. Two requests had failed — both related to a session cookie that Meridian's application handled in an unusual way. The PerfBrains engineer identified the pattern, explained the fix, and showed Priya where in the output Scala file to make the change. The fix took eight minutes.

Re-run validation score: 97%.

"In 45 minutes we had a production-ready Gatling script for one of our most complex flows, validated at 97%, with a clear explanation of every decision the tool had made. I knew then that this was the answer."

The proof of concept: five scripts in five days

Priya's recommendation to the director of engineering was direct: run a one-week POC, convert five representative scripts spanning the complexity range of the full estate, validate each one, and use the results to project the full migration timeline and risk profile.

The POC was scoped and agreed with the PerfBrains team the following week. Five scripts were selected — two simple (under 40 requests), two medium (80–100 requests), one complex (the batch processing flow, 160 requests, 18 correlation rules including XML response parsing).

Results at the end of the week:

ScriptRequestsCorrelationsValidation scoreManual review time
Login flow38499%25 min
Dashboard load41398%20 min
Fund transfer941296%55 min
Mortgage application891197%50 min
Batch processing1601893%2h 10 min

The batch processing script required the most review — the XML parsing correlations were complex, and three of the 18 extractors were MEDIUM confidence and needed manual verification. But even at two hours of review time, converting a 160-request script with 18 correlation rules in a single working day was a result Priya's team had not thought possible.

"Before the POC, my estimate for the batch processing script alone was three to four days minimum. We did it in one, including validation."

The business case: numbers that closed the deal

Armed with the POC results, Priya built the business case. The projection was based on the POC benchmarks extrapolated across all 94 scripts, with complexity weightings applied based on a quick audit of the full estate.

Estimated migration time with PerfBrains: six weeks, two engineers at 60% allocation alongside normal sprint work. Estimated migration time without a tool: 22 weeks, three engineers at full allocation — still risky.

The director signed off the engagement the same day. The LoadRunner renewal was not signed.

The migration: six weeks, 94 scripts

The migration ran from the second week of January to mid-February. Priya's team converted scripts in batches of eight to ten per week, prioritising by business criticality — the payment and authentication flows first, the reporting and batch scripts last.

The PerfBrains team was available throughout on a dedicated Slack channel, responding to technical questions within the business day. Two scripts required escalated support — one involving a legacy NTLM authentication flow that needed a custom extractor pattern, and one with a multi-part form upload that required manual post-processing. Both were resolved within 48 hours.

Final estate conversion results across all 94 scripts:

MetricResult
Scripts converted94 / 94
Average Tier-2 validation score96.4%
Scripts scoring ≥ 95%81 (86%)
Scripts requiring significant manual review7 (7.4%)
Scripts escalated to PerfBrains support2
Total elapsed time6 weeks
Engineer time (converting + reviewing)Approx. 340 hours across 2 engineers

The team ran the first full regression suite on the Gatling scripts against staging in week seven. Eleven scripts flagged issues — mostly related to environment-specific hostnames and one staging-only rate limiting behaviour that hadn't appeared in mock validation. All were resolved within the week.

By week eight, the Gatling suite was running in CI on every release candidate. The LoadRunner licence expired. It was not renewed.

Outcome: what changed for Meridian's performance team

"The licence saving is the headline number, but honestly it's not the most important thing," Priya says. "The most important thing is that our scripts are now in version control, they run in CI, and every developer on the team can read them. That's a complete change in how performance testing works here."

The team has since added two Gatling scripts to the suite written from scratch by developers who had never used LoadRunner — something that would have required specialist training under the old model. The CI integration means performance regressions are caught in the pull request cycle rather than in the load lab before a release.

The $380,000 that wasn't spent on the licence renewal funded a new observability stack and a headcount addition to the platform team.

"If you're sitting on a LoadRunner estate and looking at your next renewal, do what I did — book the demo, bring your actual scripts, and let the tool prove itself. The POC pays for the decision in a week."

— Priya Nair, Lead Performance Engineer, Meridian Financial

Want to see what PerfBrains does with your scripts?

Every engagement starts the same way: a 30-minute demo where we convert your actual scripts, live, so you can evaluate the output against your own codebase. No slides. No canned walkthrough.

If the demo looks promising, we scope a proof of concept together — typically five to ten scripts across your complexity range — and use the results to build your migration plan and commercial proposal.

Book a demo →