DEV Community

Cover image for Master API Load Testing with Artillery.io: Your APIs Under Fire πŸ”₯
Laxman Rathod
Laxman Rathod

Posted on

Master API Load Testing with Artillery.io: Your APIs Under Fire πŸ”₯

Discover how to stress-test your APIs like a pro using Artillery's powerful cloud platform

Hey developers! πŸ‘‹ Ever launched an API only to watch it crumble under real-world traffic? We've all been there. Today, we're diving into Artillery.io - the modern load testing tool that'll help you build bulletproof APIs. Whether you're a startup founder or a seasoned engineer, this guide will get you load testing like a pro in minutes, not hours.

Why Load Testing Matters in 2025

Picture this: Your app goes viral overnight, traffic spikes 10x, and your API starts returning 500 errors faster than you can say "server overload." Sound familiar?

Real-world scenarios where load testing saves the day:

  • Black Friday traffic surges
  • Viral social media mentions
  • Product Hunt launches
  • Marketing campaign success

Artillery.io makes load testing as simple as writing a config file. No complex setups, no infrastructure headaches - just pure performance insights.

What is Artillery.io? 🎯

Artillery.io is a modern, developer-friendly load testing platform that's evolved far beyond its CLI roots. The latest version offers:

  • Cloud-based testing - No local resource limitations
  • Real browser testing - Not just HTTP requests
  • Beautiful dashboards - Actionable insights, not just numbers
  • CI/CD integration - Automated performance testing
  • Global load generation - Test from multiple regions

Think of it as the "Vercel for load testing" - simple, powerful, and built for modern development workflows.

Getting Started: Your First Load Test

Step 1: Setting Up Artillery.io

First, let's get Artillery installed and ready:

# Install Artillery globally
pnpm add -g artillery@latest

# Verify installation
artillery --version
Enter fullscreen mode Exit fullscreen mode

Create a free account at artillery.io to access the cloud features - trust me, it's worth it!

Step 2: Your First Test Configuration

Create a file called basic-load-test.yml:

config:
  target: "https://jsonplaceholder.typicode.com"
  phases:
    - duration: 60
      arrivalRate: 5
      name: "Warm up"
    - duration: 120
      arrivalRate: 20
      name: "Sustained load"
    - duration: 60
      arrivalRate: 50
      name: "Peak traffic"

scenarios:
  - name: "Get posts"
    weight: 70
    flow:
      - get:
          url: "/posts"
      - think: 2
      - get:
          url: "/posts/{{ $randomInt(1, 100) }}"

  - name: "Create post"
    weight: 30
    flow:
      - post:
          url: "/posts"
          json:
            title: "Test Post {{ $randomString() }}"
            body: "This is a test post from Artillery"
            userId: "{{ $randomInt(1, 10) }}"
Enter fullscreen mode Exit fullscreen mode

Step 3: Running Your First Test

# Run locally (great for development)
artillery run basic-load-test.yml

# Run on Artillery Cloud (recommended)
artillery run-cloud basic-load-test.yml
Enter fullscreen mode Exit fullscreen mode

Boom! πŸŽ‰ You just ran your first load test. Artillery will show you real-time metrics including response times, error rates, and throughput.

Understanding Your Results πŸ“Š

Artillery provides several key metrics:

Response Time Metrics

Response time:
  min: 45ms
  max: 1.2s
  mean: 120ms
  p95: 340ms
  p99: 670ms
Enter fullscreen mode Exit fullscreen mode

What this means:

  • mean (120ms): Half of requests were faster than this
  • p95 (340ms): 95% of requests were faster than this
  • p99 (670ms): Only 1% of requests were slower than this

HTTP Status Codes

Codes:
  200: 2847 (95.6%)
  500: 131 (4.4%)
Enter fullscreen mode Exit fullscreen mode

Red flags to watch for:

  • High 4xx rates (client errors)
  • Any 5xx rates (server errors)
  • Timeouts or connection errors

Advanced Testing Scenarios

Testing with Authentication

config:
  target: "https://your-api.com"
  phases:
    - duration: 60
      arrivalRate: 10

scenarios:
  - name: "Authenticated requests"
    flow:
      # Login first
      - post:
          url: "/auth/login"
          json:
            email: "test@example.com"
            password: "password123"
          capture:
            - json: "$.token"
              as: "authToken"

      # Use the token
      - get:
          url: "/protected-resource"
          headers:
            Authorization: "Bearer {{ authToken }}"
Enter fullscreen mode Exit fullscreen mode

Database-Heavy Operations

scenarios:
  - name: "CRUD operations"
    flow:
      # Create
      - post:
          url: "/api/users"
          json:
            name: "{{ $randomString() }}"
            email: "{{ $randomString() }}@test.com"
          capture:
            - json: "$.id"
              as: "userId"

      # Read
      - get:
          url: "/api/users/{{ userId }}"

      # Update
      - put:
          url: "/api/users/{{ userId }}"
          json:
            name: "Updated {{ $randomString() }}"

      # Delete
      - delete:
          url: "/api/users/{{ userId }}"
Enter fullscreen mode Exit fullscreen mode

File Upload Testing

scenarios:
  - name: "File uploads"
    flow:
      - post:
          url: "/api/upload"
          formData:
            file: "@./test-file.pdf"
            description: "Load test upload"
Enter fullscreen mode Exit fullscreen mode

Artillery Cloud: The Game Changer ☁️

The cloud platform takes Artillery to the next level:

Global Load Generation

# Test from multiple regions
artillery run-cloud basic-load-test.yml --region us-east-1,eu-west-1,ap-southeast-1
Enter fullscreen mode Exit fullscreen mode

Real Browser Testing

config:
  target: "https://your-app.com"
  engines:
    playwright: {}

scenarios:
  - engine: playwright
    flow:
      - goto:
          url: "/"
      - click:
          selector: "#login-button"
      - type:
          selector: "#email"
          text: "test@example.com"
      - type:
          selector: "#password"
          text: "password123"
      - click:
          selector: "#submit"
      - waitForSelector:
          selector: "#dashboard"
Enter fullscreen mode Exit fullscreen mode

Monitoring Integration

config:
  target: "https://your-api.com"
  plugins:
    statsd:
      host: your-statsd-server
    datadog:
      apiKey: your-datadog-key
Enter fullscreen mode Exit fullscreen mode

Best Practices for Effective Load Testing

1. Start Small, Scale Gradually

# Good: Gradual ramp-up
phases:
  - duration: 30
    arrivalRate: 1
    name: "Baseline"
  - duration: 60
    arrivalRate: 10
    name: "Normal load"
  - duration: 30
    arrivalRate: 50
    name: "Peak load"

# Avoid: Instant high load
phases:
  - duration: 60
    arrivalRate: 100  # Too aggressive!
Enter fullscreen mode Exit fullscreen mode

2. Test Realistic User Journeys

scenarios:
  - name: "Typical user flow"
    flow:
      - get:
          url: "/"
      - think: 3 # User reads the page
      - post:
          url: "/search"
          json:
            query: "{{ $randomString() }}"
      - think: 2
      - get:
          url: "/results/{{ $randomInt(1, 10) }}"
Enter fullscreen mode Exit fullscreen mode

3. Monitor Both Client and Server

# Monitor your infrastructure while testing
artillery run-cloud test.yml &
docker stats  # or your monitoring tool
Enter fullscreen mode Exit fullscreen mode

4. Set Up Proper Test Data

config:
  payload:
    path: "test-data.csv"
    fields:
      - "userId"
      - "email"
      - "productId"

scenarios:
  - flow:
      - post:
          url: "/api/orders"
          json:
            userId: "{{ userId }}"
            productId: "{{ productId }}"
Enter fullscreen mode Exit fullscreen mode

Integrating with Your CI/CD Pipeline

GitHub Actions Example

name: Load Test
on:
  push:
    branches: [main]

jobs:
  load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Artillery
        run: npm install -g artillery@latest
      - name: Run Load Test
        run: artillery run-cloud load-test.yml
        env:
          ARTILLERY_CLOUD_API_KEY: ${{ secrets.ARTILLERY_API_KEY }}
Enter fullscreen mode Exit fullscreen mode

Performance Budgets

config:
  ensure:
    p95: 200 # 95th percentile under 200ms
    p99: 500 # 99th percentile under 500ms
    errorRate: 1 # Less than 1% errors
Enter fullscreen mode Exit fullscreen mode

Analyzing and Acting on Results

Interpreting Common Patterns

πŸ”΄ Response Time Climbing

Phase 1: 100ms average
Phase 2: 200ms average
Phase 3: 500ms average
Enter fullscreen mode Exit fullscreen mode

Action: Investigate database queries, add caching

πŸ”΄ Error Rate Spike

0-30 seconds: 0% errors
30-60 seconds: 15% errors
Enter fullscreen mode Exit fullscreen mode

Action: Check rate limiting, database connections

🟒 Healthy Performance

Consistent response times across all phases
Error rate < 1%
No connection timeouts
Enter fullscreen mode Exit fullscreen mode

Setting Up Alerts

config:
  ensure:
    p99: 1000
    errorRate: 5
  # Fail the test if thresholds exceeded
Enter fullscreen mode Exit fullscreen mode

Pro Tips for Production Testing

1. Test Production-Like Environment

# Use staging environment that mirrors production
artillery run-cloud test.yml --target https://staging-api.yourapp.com
Enter fullscreen mode Exit fullscreen mode

2. Coordinate with Your Team

# Schedule tests to avoid conflicts
artillery run-cloud test.yml --note "Weekly performance regression test"
Enter fullscreen mode Exit fullscreen mode

3. Test Edge Cases

scenarios:
  - name: "Large payload test"
    flow:
      - post:
          url: "/api/data"
          json:
            data: "{{ $randomString(10000) }}" # Large string
Enter fullscreen mode Exit fullscreen mode

Troubleshooting Common Issues

High Response Times

  • Check database query performance
  • Verify caching is working
  • Monitor memory usage

Connection Errors

  • Check server connection limits
  • Verify load balancer configuration
  • Monitor network latency

Inconsistent Results

  • Use cloud testing for consistent resources
  • Run multiple test iterations
  • Check for external dependencies

What's Next?

Ready to level up your load testing game? Here are some advanced topics to explore:

  • Custom metrics collection with plugins
  • Distributed testing across multiple regions
  • Performance regression testing in CI/CD
  • Real user monitoring integration
  • Chaos engineering with Artillery

Wrapping Up

Congratulations! πŸŽ‰ You're now equipped with the knowledge to stress-test your APIs like a seasoned performance engineer. Artillery makes what used to be complex infrastructure problems into simple configuration files.

Key takeaways:

  • Start with simple tests and gradually increase complexity
  • Use Artillery Cloud for consistent, scalable testing
  • Monitor both application and infrastructure metrics
  • Integrate load testing into your development workflow
  • Test realistic user scenarios, not just endpoint hammering

Remember: Load testing isn't about breaking your API (though that's fun too πŸ˜„) - it's about understanding your system's limits and building confidence in your infrastructure.


Found this helpful? Hit that ❀️ and follow me for more performance engineering insights!

What's your biggest API performance challenge? Drop a comment below - I love hearing from fellow developers and might write about your specific use case next!

Keep building awesome stuff! πŸš€

Top comments (0)