Why I Switched to Artillery for Performance Testing
For years, I relied on heavy GUI-based tools for performance testing, but they always felt clunky and disconnected from my CI/CD pipeline. When I first discovered Artillery, it changed my workflow. It’s a modern, Node.js-based toolkit that lets you define your load tests as code (YAML), making them versionable and reproducible. In this artillery load testing tutorial, I’m going to show you exactly how to move from ‘hoping it works’ to ‘knowing it scales’.
Before we dive into the tooling, if you’re completely new to the concept of stress testing, I highly recommend reading my guide on performance testing for beginners to understand the difference between load, stress, and soak testing.
Prerequisites
- Node.js installed: Artillery runs on Node.js. Ensure you have the LTS version installed.
- A Target API: An endpoint you own or a staging environment. Never load test a production API you don’t control.
- Terminal Access: Bash, Zsh, or PowerShell.
Step 1: Installing Artillery
Installation is straightforward. I prefer installing it globally so I can run tests from any directory in my project.
npm install -g artillery
Verify the installation by checking the version:
artillery version
Step 2: Creating Your First Load Test Script
Artillery uses YAML files to define the scenario. I find this much cleaner than writing complex JS loops to simulate users. Create a file named load-test.yml in your project root.
config:
target: "https://api.example.com"
phases:
- duration: 60
arrivalRate: 5
name: Warm up
- duration: 120
arrivalRate: 20
name: Sustained load
scenarios:
- name: "Get User Profile"
flow:
- get:
url: "/v1/profile"
Breaking down the config:
- Target: The base URL of your API.
- Phases: This is where the magic happens. In the example above, I’ve defined a ‘Warm up’ phase (5 users arriving per second for 1 minute) and a ‘Sustained load’ phase (20 users per second for 2 minutes).
- Scenarios: The actual sequence of requests a virtual user performs.
Step 3: Running the Test and Analyzing Results
To execute the test, run the following command in your terminal:
artillery run load-test.yml
As the test runs, you’ll see a live summary. Once finished, Artillery provides a detailed report. As shown in the terminal output image below, you should focus on the p95 and p99 latency figures. If your p99 is significantly higher than your average, you likely have an intermittent bottleneck or a cold-start issue.
Step 4: Simulating Realistic User Behavior
Real users don’t just hit one endpoint; they navigate a flow. I usually simulate a full user journey: Login → Fetch Data → Update Profile. Here is how you handle dynamic data using a CSV payload.
First, create a users.csv file with columns for username and password. Then, update your YAML:
config:
target: "https://api.example.com"
payload:
- users.csv
phases:
- duration: 60
arrivalRate: 10
scenarios:
- name: "User Login Flow"
flow:
- get:
url: "/login"
json: "{{ username }}"
- think: 2
- get:
url: "/dashboard"
Note the think command. In my experience, omitting ‘think time’ leads to unrealistic spikes that don’t mirror human behavior. If you are testing a frontend-heavy application, you might also want to check out my react app performance testing guide to see how the client-side handles this load.
Pro Tips for Better Load Tests
- Test from a different region: Don’t run Artillery from your laptop if your server is in AWS us-east-1. The network latency will skew your results. Use a small EC2 instance in the same region for ‘internal’ testing and a different region for ‘external’ testing.
- Monitor your DB: Load testing isn’t just about API response times. I always keep a database monitor (like AWS CloudWatch or pgAdmin) open to see if CPU spikes or lock contentions are the real culprit.
- Use the Playwright Integration: If you need to test the actual browser rendering under load, Artillery integrates with Playwright. It’s heavier on resources but far more accurate for UX.
Troubleshooting Common Issues
| Issue | Probable Cause | Solution |
|---|---|---|
ECONNRESET errors |
Server is dropping connections | Check your server’s keep-alive settings or increase the connection limit. |
| High latency on local machine | CPU throttling on your laptop | Run Artillery from a Linux VPS or a dedicated CI runner. |
| 429 Too Many Requests | Rate limiting is active | Disable rate limiting for your test IP or adjust your arrivalRate. |
What’s Next?
Now that you’ve mastered the basics of this artillery load testing tutorial, the next step is automation. I recommend integrating Artillery into your GitHub Actions or GitLab CI pipeline. By setting a ‘fail’ threshold (e.g., if p95 latency > 500ms, fail the build), you can prevent performance regressions from ever hitting production.
Ready to scale your testing? Start by auditing your current API endpoints and creating a suite of scenarios that mirror your most critical user paths.