JMeter Tutorial for Beginners 2026: Complete Guide
Complete JMeter tutorial for beginners in 2026. Installation, first test plan, thread groups, samplers, listeners, assertions, CSV parameterization, distributed runs, CI/CD, and HTML report generation.

Last updated: June 29, 2026 · Reading time: 9 minutes · By SoftwareTestPilot Editorial Team
What you'll build: A working JMeter 5.6.3 install, your first test plan against a real API, a parameterized load test with CSV data, distributed runs, and a CI/CD pipeline that uploads the HTML report as an artifact on every pull request.
What is JMeter?
Apache JMeter is a 100% pure Java open-source load testing tool. It supports HTTP, HTTPS, SOAP, REST, FTP, LDAP, JDBC, and many other protocols. For broader context, see the in-depth JMeter Performance Testing Step-by-Step Guide and our k6 vs JMeter comparison.
Step 1 — Prerequisites
- Java 17 or 21 LTS — get a build from Adoptium.
- 8 GB RAM minimum (16 GB for serious tests)
- JMeter 5.6.3 — latest stable in 2026
Step 2 — Install JMeter
macOS
brew install openjdk@17
brew install jmeter
jmeter --versionUbuntu / Debian
sudo apt update
sudo apt install openjdk-17-jdk
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.6.3.tgz
tar -xzf apache-jmeter-5.6.3.tgz
sudo mv apache-jmeter-5.6.3 /opt/
export PATH=$PATH:/opt/apache-jmeter-5.6.3/binWindows
Download from jmeter.apache.org, extract the archive, and add the bin/ folder to your PATH.
Verify with jmeter --version — you should see 5.6.3.
Launch the GUI
jmeterThe GUI opens with an empty Test Plan. For serious work, use CLI mode (covered below).
Step 3 — Your First Test Plan
Add a Thread Group
Right-click Test Plan → Add → Threads (Users) → Thread Group.
| Property | Value |
|---|---|
| Number of Threads (users) | 50 |
| Ramp-Up Period (seconds) | 10 |
| Loop Count | 20 |
Add an HTTP Request Sampler
Right-click the Thread Group → Add → Sampler → HTTP Request.
| Property | Value |
|---|---|
| Protocol | https |
| Server Name or IP | jsonplaceholder.typicode.com |
| HTTP Request | GET |
| Path | /users/1 |
Add a Duration Assertion
Right-click the HTTP Request → Add → Assertions → Duration Assertion. Set 2000 ms — anything slower fails.
Add a Response Assertion
| Property | Value |
|---|---|
| Field to Test | Response Code |
| Pattern Matching Rules | Matches |
| Patterns to Test | 200 |
Add a Summary Report
Right-click the Thread Group → Add → Listener → Summary Report.
Run the test
Click the green Run button (or Ctrl+R). Watch the Summary Report fill with metrics.
Run in CLI mode
Save the plan as first-plan.jmx, then:
jmeter -n -t first-plan.jmx -l result.jtl -e -o report/Open report/index.html in a browser to see the interactive HTML dashboard.
Step 4 — Parameterize Test Data
Hard-coded inputs are an anti-pattern. Use the CSV Data Set Config.
Create users.csv:
user_id,email
1,admin@example.com
2,user@example.com
3,guest@example.comThen add Config Element → CSV Data Set Config:
| Property | Value |
|---|---|
| Filename | users.csv |
| Variable Names | user_id,email |
In the HTTP Request path, replace 1 with ${user_id}.
Add a realistic timer
Right-click the HTTP Request → Add → Timer → Uniform Random Timer. Set Constant Delay Offset = 200 ms and Random Delay Maximum = 100 ms. This simulates real user pacing instead of synchronized hammering.
Step 5 — Run a Realistic Load Test
| Property | Value |
|---|---|
| Number of Threads | 1000 |
| Ramp-Up Period | 60 seconds |
| Loop Count | 100 |
jmeter -n -t load-test.jmx -l result.jtl -e -o report/Step 6 — Distributed Load Testing
For more than ~1,000 concurrent users, distribute load across machines.
1. Configure master in jmeter.properties:
remote_hosts=slave1.example.com,slave2.example.com
client.rmi.localport=500002. Start each slave:
jmeter-server3. Run from master:
jmeter -n -t test.jmx -r -l result.jtl -e -o report/For deeper distributed setup, see the full JMeter Tutorial.
Step 7 — CI/CD with GitHub Actions
name: JMeter Load Test
on: [pull_request]
jobs:
load:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: '17' }
- run: |
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.6.3.tgz
tar -xzf apache-jmeter-5.6.3.tgz
- run: ./apache-jmeter-5.6.3/bin/jmeter -n -t test.jmx -l result.jtl -e -o report/
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: jmeter-report
path: report/Step 8 — Best Practices
Do
- Use CLI mode for any real load
- Use realistic ramp-up (1 thread per 100–500 ms)
- Parameterize test data with CSV
- Add assertions to verify behavior
- Generate HTML reports for stakeholders
- Use distributed runs for >1,000 users
Don't
- Don't run heavy load in the GUI
- Don't hard-code values that change per environment
- Don't add View Results Tree to heavy tests — it leaks memory
- Don't run load generators on Wi-Fi in CI
Step 9 — Common Errors
java.lang.OutOfMemoryError: Java heap space
Increase JVM memory:
export JVM_ARGS="-Xms1g -Xmx4g -XX:+UseG1GC"Connection refused
Verify the target server is up and your network allows the connection.
Non HTTP response code: java.net.SocketTimeoutException
Increase connect and response timeouts in the HTTP Request Defaults.
Step 10 — Advanced Techniques
1. Correlation for dynamic values
Add a Regular Expression Extractor to the HTTP Request:
Reference Name: authToken
Regular Expression: "token":"(.+?)"
Template: $1$Then reuse with ${authToken} in the next request.
2. JSON Path Extractor
Variable Names: userId
JSON Path: $.data.id
Default Value: NOT_FOUND3. Conditional controllers
If Controller: ${JMeterThread.last_sample_ok}4. Loop controllers
Loop Controller: 10 // wrap child requests5. Data-driven testing with CSV
CSV Data Set Config
Filename: users.csv
Variable Names: username,password
Recycle on EOF: true6. Custom assertions with Groovy
// JSR223 Assertion
if (vars.get("responseTime") as int > 1000) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage("Response time > 1000ms")
}