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

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:

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.

Artillery terminal output showing p95 and p99 latency results
Artillery terminal output showing p95 and p99 latency results

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

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.