javascript

Performance and Stress Testing in Node.js

Antonello Zanini

Antonello Zanini on

Performance and Stress Testing in Node.js

Performance and stress testing are two popular testing methodologies. They focus on determining how an application behaves under regular and unexpectedly high traffic, respectively. These tests are essential for assessing a system's robustness and scalability, particularly in applications with fluctuating traffic like Node.js backends.

In this article, you'll learn about stress and performance testing, why they're important, the best tools available, and how to use them in Node.

Let's dive in!

What Is Performance and Stress Testing?

Performance testing is the process of evaluating a system's responsiveness, stability, and scalability under normal or given load conditions. The goal of this testing method is to ensure that an application meets the expected performance requirements.

Stress testing is more specific and involves pushing a system beyond its normal capacity to identify breaking points. The objective is to observe how an application behaves under extreme conditions, such as unexpected spikes in traffic or workloads.

Stress testing can be considered a specific type of performance testing. While performance tests focus on evaluating a system's behavior under expected loads, stress tests go further by intentionally pushing a system beyond its limits to assess how it handles edge conditions.

Since the two types of testing are related, most tools that support performance testing also empower you to conduct stress testing.

Why Performance and Stress Testing Are Important in Node.js

Most web applications backed by Node.js backends experience fluctuating traffic. Performance and stress tests guarantee that the servers can handle both normal and extreme traffic efficiently, especially in production environments.

Node stress and performance testing are essential for three reasons:

  • To evaluate the asynchronous model: Node.js handles concurrent requests through asynchronous processing. Performance tests help you understand how well your backend performs under typical concurrency. They highlight when performance starts to degrade, allowing you to take proactive measures, like configuring additional rate limiters to manage traffic spikes. For more details, read our tutorial on implementing rate limiting in Node.
  • To assess scalability limitations: Node relies on a non-blocking, single-threaded event loop, which can easily become a limiting factor when handling high traffic volumes. Stress testing helps you assess a system's performance under heavy loads and determine whether to use clustering or other scaling techniques to improve performance.
  • To optimize resource utilization: Performance testing analyzes how your application utilizes system resources, such as CPU, memory, and network. This is key to identifying bottlenecks, understanding how to scale servers, and where to deploy an application.

Best Node Tools For Performance and Stress Testing

There is a wide range of Node tools available for stress and performance testing. In general, they're versatile and can be used to test most web applications, regardless of the programming language they're built with.

In this guide, we'll evaluate Node performance and stress testing tools using the following criteria:

  • Features: The capabilities and functionalities offered by the testing tool.
  • GitHub stars: A measure of the tool's popularity, represented by the number of stars on its GitHub repository.
  • Downloads: The monthly number of downloads, reflecting the tool's usage and adoption.
  • Pricing: Details about the cost of the tool.

We'll also show you how to quickly set up and get started with each tool.

For a quick overview of how these tools compare, check out the summary table below:

Testing ToolProgramming LanguageTargetGitHub StarsDownloadsFree PlanPremium Plans
AutoCannonNode.jsHTTP/1.1 endpointsOver 8kOver 200k weeklyYes
ArtilleryNode.jsHTTP APIs, WebSocket, Socket.IO, gRPC, or Kinesis APIs, browser applicationsOver 8.4kOver 90k weeklyYesStarts at $499/month
k6Go, but supports scripting in Node.jsHTTP, WebSocket, gRPC, browser applicationsOver 27kOver 71k weeklyYesPay As You Go starts at $19/month, Premium at $299/month

Let's now dive into these tools!

AutoCannon

AutoCannon homepage

AutoCannon is a Node-based HTTP/1.1 benchmarking tool available as both a CLI utility and a programmatic API. Inspired by popular benchmarking tools like wrk and wrk2, it supports HTTP pipelining and HTTPS.

AutoCannon is available through the autocannon npm package. You can install it globally with this command:

Shell
npm install autocannon -g

For detailed usage instructions, whether for the command line or within code, refer to the official AutoCannon documentation.

🛠️ Features:

  • Support for HTTP/1.1 endpoints
  • Incorporates benchmarking features from wrk and wrk2
  • Support for HTTP pipelining to execute multiple requests on a single connection
  • Dedicated Node.js API
  • CLI tool with rich options
  • Performs statistical analysis of results
  • Support for custom SSL certificates and advanced debugging options
  • Options to exclude error stats and enforce response body expectations
  • In-depth reporting and error diagnostics with verbose and debug mode

GitHub stars: Over 8k stars

📥 Downloads: Over 200k weekly downloads on npm

💰 Pricing: Free

Artillery

Artillery homepage
Artillery is a Node-powered performance testing tool that supports built-in serverless distributed load testing. It allows you to run production-scale, multi-region load tests without managing the underlying infrastructure.

Artillery works with your AWS or Azure account, requiring no DevOps expertise. It enables you to test HTTP APIs, WebSocket, Socket.IO services, and complex web applications through headless browsers. Install it globally on your machine via the artillery npm package, as follows:

Shell
npm install -g artillery@latest

🛠️ Features:

  • Cloud-native, distributed solution for load, performance, and stress testing at scale
  • No DevOps required—scale load tests seamlessly on AWS Lambda or AWS Fargate with zero infrastructure setup
  • Test scripts written in simple YAML files
  • Integration with Playwright for real headless browser testing
  • 20+ integrations for monitoring, observability, and CI/CD
  • Artillery CLI with rich options for test execution and management
  • Supports testing for HTTP, WebSocket, Socket.IO, gRPC, Kinesis, and more
  • Emulate complex user behavior with request chains, multiple steps, transactions, and more
  • Extendable through a dedicated plugin API

GitHub stars: 8.4k stars

📥 Downloads: Over 90k weekly downloads

💰 Pricing:

  • Free Plan: For teams just starting with load testing or those working on internal proof-of-concept projects.
  • Artillery Cloud: Starts at $499/month. Ideal for teams conducting continuous load tests on production applications.

k6

k6 homepage

Grafana k6 is an open-source, developer-friendly, and extensible load testing tool. Built on years of performance and testing experience, k6 offers a powerful, full-featured solution for performance testing focused on providing the best developer experience. While it is built in Go for performance, it supports scripting in Node.js for familiarity.

For installation and setup instructions for k6 on your operating system, refer to the official k6 documentation.

🛠️ Features:

  • Configurable load generation to allow even lower-end machines to simulate heavy traffic
  • Support for reusable scripts, modularized logic, and version control
  • Integration with your CI/CD automation tools
  • Full-featured JavaScript scripting API to simulate real application traffic
  • Support for HTTP, WebSockets, gRPC, browser applications, and more
  • Extendable software via community plugins
  • Summary statistics and granular metrics
  • Exportable metrics
  • Native integration with Grafana Cloud for test execution, metrics correlation, data analysis, and more

⭐ GitHub stars: Over 27k stars

📥 Downloads: Over 71k weekly downloads

💰 Pricing:

  • Free Forever: Always $0 for all Grafana Cloud features with capped usage limits and community support only
  • Pro Pay As You Go: Starts at $19/month for all Grafana Cloud features, optional Enterprise plugins, extended usage limits, and 8/5 support
  • Advanced Premium Bundle: Starts at $299/month for all Grafana Cloud features, includes Enterprise plugins, higher usage limits, and 24/7 support

How To Perform Stress Testing in Node.js

Follow this step-by-step guide to perform performance testing in Node.

The application we will test is a simple Node.js backend that exposes a "Hello World" endpoint. We'll be using AutoCannon as our testing tool, but you can easily adapt this example to other tools.

If you're interested in a different setup, read our guide on how to perform load testing with Artillery.

Time to write performance and stress tests for your backend JavaScript application!

Step #1: Project Setup

First, make sure you have the latest LTS version of Node installed on your machine. Then, open your terminal and create a directory for your project:

Shell
mkdir node-performance-test-demo-app

Enter the project's folder and initialize an npm project with the init npm command:

Shell
cd node-performance-test-demo-app npm init -y

This will generate a package.json file with default values.

Now, create a file called server.js and add the following code to define a "Hello World" endpoint using vanilla Node.js:

JavaScript
const http = require("http"); // create an HTTP server const server = http.createServer((req, res) => { // responds with "Hello, World!" at the "/api/v1/hello-world" endpoint // and 404 in all other cases if (req.url === "/api/v1/hello-world" && req.method === "GET") { res.statusCode = 200; res.setHeader("Content-Type", "application/json"); res.end("Hello, World!"); } else { res.statusCode = 404; res.setHeader("Content-Type", "application/json"); res.end("Not Found"); } }); // server details const hostname = "localhost"; const port = 3000; // run the server server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });

In the script above, the built-in http module initializes a simple web server. This listens on port 3000 and responds with "Hello, World!" when users visit the /api/v1/hello-world endpoint.

Verify it by launching the server with:

Shell
node server.js

Your backend should now be listening locally on port 3000.

Next, perform a curl request to /api/v1/hello-world:

Shell
curl "http://localhost:3000/api/v1/hello-world"

Note: If you're a Windows user, replace curl with curl.exe.

The result will be:

JSON
"Hello, World!"

Wonderful! You now have an application that exposes an HTTP endpoint to test with AutoCannon.

Step #2: Install AutoCannon

Execute the command below to install AutoCannon globally:

Shell
npm install -g autocannon

Verify that it works by running in the terminal:

Shell
autocannon

If you want to add it as a project's dependency, instead run:

Shell
npm install autocannon

This time, you can launch AutoCannon in the CLI with:

Shell
npx autocannon

In both cases, the output will be:

Shell
Usage: autocannon [opts] URL URL is any valid HTTP or HTTPS URL. If the PORT environment variable is set, the URL can be a path. In that case 'http://localhost:$PORT/path' will be used as the URL. Available options: -c/--connections NUM # omitted for brevity...

Amazing! Get ready to performance test your application.

Step #3: Run a Performance Test

While the server is running, open a new terminal window and run the command below to launch a performance test with AutoCannon:

Shell
autocannon "http://localhost:3000/api/v1/hello-world"

The testing tool will send requests to the "Hello, World!" endpoint for 10 seconds using 10 concurrent connections (the default settings).

You can modify the test parameters by specifying particular CLI options in the command. For example, run the test with 50 concurrent connections for 30 seconds with:

Shell
autocannon -c 50 -d 30 http://localhost:3000

-c defines the number of concurrent connections, while -d sets the duration of the performance test in seconds.

Fantastic! Now all that remains is to inspect the results of the test!

Step #4: Analyze the Results

The output produced by AutoCannon will be:

Shell
Running 30s test @ http://localhost:3000/api/v1/hello-world 50 connections ┌─────────┬──────┬──────┬───────┬───────┬─────────┬────────┬───────┐ Stat 2.5% 50% 97.5% 99% Avg Stdev Max ├─────────┼──────┼──────┼───────┼───────┼─────────┼────────┼───────┤ Latency 1 ms 4 ms 9 ms 12 ms 4.24 ms 2.3 ms 82 ms └─────────┴──────┴──────┴───────┴───────┴─────────┴────────┴───────┘ ┌───────────┬────────┬────────┬─────────┬─────────┬──────────┬─────────┬────────┐ Stat 1% 2.5% 50% 97.5% Avg Stdev Min ├───────────┼────────┼────────┼─────────┼─────────┼──────────┼─────────┼────────┤ Req/Sec 4,567 4,567 10,679 13,423 10,549.4 2,119.6 4,564 ├───────────┼────────┼────────┼─────────┼─────────┼──────────┼─────────┼────────┤ Bytes/Sec 767 kB 767 kB 1.79 MB 2.26 MB 1.77 MB 356 kB 767 kB └───────────┴────────┴────────┴─────────┴─────────┴──────────┴─────────┴────────┘ Req/Bytes counts sampled once per second. of samples: 30 317k requests in 30.05s, 53.2 MB read

This provides performance statistics such as requests per second (RPS), bytes per second (BPS), response time, and latency.

Et voilà! You just performed performance testing with Node.js using AutoCannon. By configuring the parameter in the CLI command, you can study how your application behaves under simulated stress scenarios.

Wrapping Up: Make Your Node Application More Reliable Than Ever

In this blog post, we explored the importance of performance and stress testing in Node.js to understand how production applications behave under different conditions.

Here's what you've learned:

  • Why stress testing is a specific type of performance testing
  • Why you should integrate both performance and stress testing into your backend
  • The best stress and performance testing tools for Node
  • How to use them in a real-world example

Thanks for reading!

Wondering what you can do next?

Finished this article? Here are a few more things you can do:

  • Share this article on social media
Antonello Zanini

Antonello Zanini

Guest author Antonello is a software engineer, but prefers to call himself a Technology Bishop. Spreading knowledge through writing is his mission.

All articles by Antonello Zanini

Become our next author!

Find out more

AppSignal monitors your apps

AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!

Discover AppSignal
AppSignal monitors your apps