7 ways to improve Node.js performance at scale - LogRocket Blog (2024)

Node.js is a solution for executing JavaScript code outside a browser. The versatility and flexibility of JavaScript on the server side enable you to develop highly performant applications.

7 ways to improve Node.js performance at scale - LogRocket Blog (1)

In this tutorial, we’ll explore Node’s efficiency and performance and show how it can help you achieve better results with fewer resources. We’ll focus primarily on caching, using a load balancer and WebSockets, and monitoring your application. By the end of this guide, you’ll have the tools and approaches you need to build a Node.js application that performs well at scale.

Module bundlers and task runners

On the front end, it’s imperative that whatever is shipped to the browser is as small as possible. This especially includes images, JavaScript, and CSS files. The process that makes this possible involves module bundlers (e.g., webpack, Parcel, Rollup) and task runners (e.g., Gulp, Grunt, etc.).

Module bundlers are build tools for processing groups of modules and their dependencies into a file or group of files. Under the hood, this all happens using Node.js. The output of such minification can then be deployed to production. The minification process can vary depending on the tool you use, but for the most part, you can use the standardized format for code modules included in the ES6 revision of JavaScript.

This allows for complex transforms, such as shortening multicharacter variable names or using a shorter syntax that’s equivalent to the original code and combining several JavaScript files into one to reduce the number of network requests. This also applies to CSS minification; the extra whitespace and comments are removed to help the browser parse it faster.

CSS modules and preprocessors

In the context of reducing browser requests during page load, CSS is no different when it comes to minification. CSS preprocessors such as PostCSS, Sass, and LESS provide variables, functions, and mix-ins to simplify the maintenance of CSS code and make refactoring less challenging. Furthermore, they compile all files into a single .css file, which reduces the number of round trips the browser has to make to serve the file.

With modern tooling that runs on Node.js, such as the aforementioned bundlers, scoped CSS names can be converted into global unique names. Now loading a CSS module to the local scope of your component is as simple as requiring or importing it like you would with any other JavaScript module.

Images

Images are another thing to consider when shipping code to the browser. Generally speaking, the lighter your images, the better. You might want to use compressed images or serve different images, depending on the device. One example that comes to mind is Gatsby, which is powered by Node.js behind the scenes and has a slew of plugins that leverage Node, some of which are specifically designed to transform images at build time into smaller ones and serve them on demand.

2. SSL/TLS and HTTP/2

When building a Node.js application, you can use HTTP/2 to make web browsing faster and easier and minimize bandwidth usage. HTTP/2 focuses on improving performance and solving issues associated with HTTP/1.x.

Features of HTTP/2 include:

  • Header compression – This removes unnecessary headers and forces all HTTP headers to be sent in compressed format.
  • Multiplexing- This allows multiple requests to retrieve resources and response messages in a single TCP connection simultaneously.

The goal of multiplexing is to minimise the number of requests made to the server. The amount of time required to create an HTTP connection is often more costly than the amount of time required to transmit the data itself. To utilise HTTP/2, there is a need to implement Transport Layer Security (TLS) and Secure Socket Layer (SSL) protocols. Node.js’ core implementation here makes it very easy to setup an HTTP/2 server.

3. Caching

Caching is a common technique to improve app performance. It’s done both on the client and server side. Client-side caching is the temporary storing of contents such as HTML pages, CSS stylesheets, JS scripts, and multimedia contents. Client caches help limit data cost by keeping commonly referenced data locally on the browser or a content delivery network (CDN). An example of client caching is when the browser keeps frequently used data locally or data stored on a CDN. The idea is that when a user visits a site and then returns to it, the site should not have to redownload all the resources again.

HTTP makes this possible via cache headers. Cache headers come in two forms.

  1. Expires specifies the date upon which the resource must be requested again
  2. Cache-Control: max-age specifies for how many seconds the resource is valid

Unless the resource has a cache header, the browser can only re-request the resource after the cache expiry date has passed. This approach has its drawbacks. For instance, what happens when a resource changes? Somehow the cache has to be broken. You can solve this via the cache busting approach by adding a version number to the resource URL. When the URL changes, the resource is redownloaded. This is easy to do with Node.js tooling such as webpack.

Even if we enable client-side caching, the app server will still need to render data for each different user accessing the app, so there needs to be an implementation of caching on the server-side. In Node.js, you can use Redis to store temporary data, known as object caching. In most cases, you can combine client- and server-side caching to optimize performance.

Over 200k developers use LogRocket to create better digital experiencesLearn more →

4. Optimizing data handling methods

Optimization is key to performance because it simplifies system processes and boosts overall app efficiency. You might be wondering, what can be optimized in a Node.js application? Start by looking at how data is handled is. Node.js programs can be slow due to a CPU/IO-bound operation, such as a database query or slow API call.

For most Node.js applications, data fetching is done via an API request and a response is returned. How do you optimize that? One common method is pagination — i.e., separating responses into batches of content that can be browsed via selective response requests. You can us pagination to optimize the response while at the same time maintaining the greater amount of data that is passed to the user client.

Filtering is another effective approach — specifically, enabling the restriction of results by the criteria of the requester itself. Not only does this reduce the overall number of calls that are made and the results that are shown, but it also enables users to very precisely decide whether resources are provided based on their requirements. These two concepts are common in REST API design.

Underfetching and overfetching relate to how data is fetched. The former provides more data than is appropriate or useful to the client, and the latter does not respond with adequate data, often requiring a separate call to another endpoint to complete the data collection. These two can occur from the client side and can be a result of poor app scaling. GraphQL is useful against this kind of problem because the server doesn’t have to guess what it needs; the client defines their request and gets exactly what they expected.

5. Load balancing

Building performant applications that can handle a large number of incoming connections is a common challenge. A common solution is to distribute the traffic to balance the connections. This approach is known as load balancing. Fortunately, Node.js allows you to duplicate an application instance to handle more connections. This can be done on a single multicore server or through multiple servers.

To scale the Node.js app on a multicore server, you can use the introduced cluster module, which spawns new processes called workers (one for each CPU core) that all run simultaneously and connect to a single master process, allowing the processes to share the same server port. In that way, it behaves like one big, multithreaded Node.js server. You can use the cluster module to enable load balancing and distribute incoming connections according to a round-robin strategy across all the workers over an environment’s multiple CPU cores.

Another approach is to use the PM2 process manager to keep applications alive forever. This helps to avoid downtime by reloading the app whenever there’s a code change or error. PM2 comes with a cluster feature that enables you to run multiple processes across all cores without worrying about any code changes to implement the native cluster module.

The single-cluster setup has its drawbacks, and we need to prepare ourselves to switch from single-server architecture to a multiserver one with load balancing using reverse proxying. NGINX supports load balancing across multiple Node.js servers and various load balancing methods, including:

  • Round robin — A new request goes to the next server in a list
  • Least connections — A new request goes to the server that has the fewest active connections
  • IP hash — A new request goes to the server assigned to a hash of the client’s IP address.

The reverse proxy feature protects the Node.js server from direct exposure to internet traffic and gives you a great deal of flexibility when using multiple application servers.

6. Secure client-side authentication

Most web apps need to keep the state to give users a personalized experience. If users can sign in to your site, you need to hold sessions for them.

More great articles from LogRocket:

  • Don't miss a moment with The Replay, a curated newsletter from LogRocket
  • Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
  • Use React's useEffect to optimize your application's performance
  • Switch between multiple versions of Node
  • Discover how to use the React children prop with TypeScript
  • Explore creating a custom mouse cursor with CSS
  • Advisory boards aren’t just for executives. Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

When implementing stateful authentication, you would typically generate a random session identifier to store the session details on the server. To scale a stateful solution to a load-balanced application across multiple servers, you can use a central storage solution such as Redis to store session data or the IP hash method (in load balancing) to ensure that the user always reaches the same web server.

Such a stateful approach has its drawbacks. For example, limiting users to a specific server can lead to issues when that server needs some sort of maintenance.

Stateless authentication with JWT is another scalable approach — arguably, a better one. The advantage is that data is always available, regardless of which machine is serving a user. A typical JWT implementation involves generating a token when a user logs in. This token is a base64 encoding of a JSON object containing the necessary user details. The token is sent back to the client and used to authenticate every API request.

7. Using WebSockets for effective server communication

The internet has traditionally been developed around the HTTP request/response model. WebSockets are an alternative to HTTP communications in web applications. They provide a long-lived, bidirectional communication channel between the client and the server. If established, the channel is kept open, offering a very quick and persistent connection between the client and the server. Both parties can start sending data at any time with low latency and overhead.

HTTP is useful for occasional data sharing and client-driven communication that involves user interaction. With WebSockets, the server may send a message to the client without an explicit request from the client, allowing them to talk to each other simultaneously. This is great for real-time and long-lived communications. ws is a popular library for Node.js that is used to implement a WebSockets server. On the front end, JavaScript is used to establish a connection to a WebSockets-enabled server and can then listen for events. Holding a large number of connections open at the same time requires a high-competition architecture at a low cost of performance, and this is what WebSockets offers.

Conclusion

In this guide, we reviewed the effect of Node.js on frontend tools, how HTTP/2 enhances Node.js performance, specific caching solutions, and data handling methods you can use to enhance Node.js performance. Then we discussed how to achieve load balancing on a Node.js app to manage more connections, the effect of stateful and stateless client-side authentication on scalability, and, finally, how WebSockets can provide a stable connection between client and server. Now you’ve got everything you need to leverage Node.js performance capabilities and write efficient applications that your users will love.

200s only 7 ways to improve Node.js performance at scale - LogRocket Blog (4) Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third-party services are successful, try LogRocket.

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.

7 ways to improve Node.js performance at scale - LogRocket Blog (2024)

FAQs

How to improve performance of NodeJS? ›

2. Tips to Improve Node JS Performance
  1. 2.1 Monitor & Measure App Performance. ...
  2. 2.2 Reduce Latency Time Through Caching. ...
  3. 2.3 Optimize Your Data Handling Methods. ...
  4. 2.4 Load Balancing. ...
  5. 2.5 Use Timeouts. ...
  6. 2.6 Monitor in Real-Time. ...
  7. 7 Improve Throughput by Cluster. ...
  8. 2.8 Employ HTTP/2 and SSL/TLS to Make Web Browsing Faster.
Nov 3, 2023

How to check performance in node js? ›

AppMetrics. AppMetrics is an open-source, lightweight Node. Js monitoring platform that's ideal for resource-constrained applications. It helps developers gain insights into application performance via detailed metrics on CPU and memory usage, event loop behavior, HTTP requests, and garbage collection.

How do I scale my node JS application? ›

Scaling Node. js Applications for High Traffic
  1. Introduction. ...
  2. Understanding Application Scalability. ...
  3. Optimizing Database Performance. ...
  4. Implementing Caching Mechanisms. ...
  5. Load Balancing Techniques. ...
  6. Scaling with Message Queues. ...
  7. Horizontal Scaling with Containerization. ...
  8. Utilizing Content Delivery Networks (CDNs)
Nov 12, 2023

What is scalability in node JS? ›

The scalability of an application refers to its ability to handle workloads at extremes, especially when demand is high.

How to run Node js faster? ›

Consider these tips to elevate your Node.js application's performance:
  1. Optimize Your Code. ...
  2. Use a Caching Layer. ...
  3. Use Compression. ...
  4. Use Load Balancing. ...
  5. Use a Content Delivery Network (CDN) ...
  6. Optimize Database Queries. ...
  7. Use a Reverse Proxy. ...
  8. Use HTTP/2.
Jun 12, 2023

How do I speed up my node build? ›

7 Ways to Speed Up Your Node. js Development Process
  1. Utilize Typescript. By introducing types, TypeScript expands JavaScript. ...
  2. Utilize Cache. ...
  3. Go Asynchronous. ...
  4. Make Use of Gzip Compression. ...
  5. Parallelize. ...
  6. Monitor in Real-Time. ...
  7. Look Deeper.
Jun 11, 2022

How to benchmark a Node.js application? ›

  1. Sync Code. const fs = require('fs'); process.on('unhandledRejection', (err)=>{ console.error(err); }) ...
  2. Average Result. sync: 1.494ms.
  3. Async Code. const fs = require('fs'); process.on('unhandledRejection', (err)=>{ console.error(err); }) ...
  4. Average Result. async: 17.537ms.
  5. Finally you have a more accurate benchmark.

How to make node API fast? ›

12 actually useful ways to optimize Node.js performance
  1. Use Node's built-in profiler.
  2. Monitor and profile with APM.
  3. Use caching to reduce latency.
  4. Optimize your data handling methods.
  5. Use timeouts.
  6. Ensure secure client-side authentication.
  7. Improve throughput through clustering.
  8. Use a Content Delivery Network (CDN)
Jun 14, 2023

How do I make sure Node.js is working? ›

To test that you have Node.js installed correctly on your computer, open a new terminal and type node --version and you should see the current Node.js version installed. Linux: There are specific Node.js packages available for the various flavors of Linux.

Is node JS good for large scale projects? ›

It adds a layer of convention and configuration that should make it easy(er) to build large projects, involving multiple teams. Really NodeJs is powerful in its own way, Some more information, You can run multiple instance of your app under load balance to handle massive request.

How do you scale application performance? ›

Index
  1. Understand Your Application's Architecture.
  2. Use Load Balancers to Distribute Traffic.
  3. Implement Caching to Reduce Server Load.
  4. Use Auto Scaling to Handle Traffic Spikes.
  5. Steps to manage traffic spikes.
  6. Monitor Your Application's Performance and Scale Accordingly.
Mar 26, 2023

How do you scale a node pool? ›

To scale a user node pool to 0 nodes, you must disable the cluster autoscaler first. For more information, see Disable the cluster autoscaler on a node pool. To scale a user pool to 0, you can use the az aks nodepool scale in alternative to the above az aks scale command, and set 0 as your node count.

How to optimize node js code? ›

How to Optimize Node. js APIs
  1. Always Use Asynchronous Functions. ...
  2. Avoid Sessions and Cookies in APIs, and Send Only Data in the API Response. ...
  3. Optimize Database Queries. ...
  4. Optimize APIs with PM2 Clustering. ...
  5. Reduce TTFB (Time to First Byte) ...
  6. Use Error Scripts with Logging. ...
  7. Use HTTP/2 Instead of HTTP. ...
  8. Run Tasks in Parallel.
Aug 22, 2022

Is node js not scalable? ›

Yes, Node. js is scalable and can handle a large number of concurrent connections due to its asynchronous, non-blocking I/O model. However, the scalability of a Node. js application also depends on other factors such as server size, processing power, memory, and network bandwidth.

How do I get better at node JS? ›

How to Start Learning Node. js
  1. Learn JavaScript. ...
  2. Understand Why It Is Called Node. ...
  3. Understand non-blocking in Node. ...
  4. Learn the Concept of the Event Loop. ...
  5. Learn the Global Variables. ...
  6. Learn How to Use the Libraries That Come With Node. ...
  7. Learn Code Writing for Node. ...
  8. Without Using Any Frameworks, Write a Web Application on Node.
May 16, 2023

How to increase performance of js? ›

Javascript tips and tricks to Optimize Performance
  1. Use Array Filter. ...
  2. Using String replace function to replace all the values. ...
  3. Use breakpoints and Console for Debugging. ...
  4. Convert to floating number without killing performance. ...
  5. Using length to delete empty in an array. ...
  6. Merging arrays without causing server load.

What makes NodeJS so fast? ›

The primary reason why NodeJS is fast because of its non-blocking I/O model. NodeJS utilizes a single asynchronous thread to handle all requests made. This reduces the CPU workload and avoids HTTP congestion and takes up less memory as well.

What is the best way to run node JS? ›

The usual way to run a Node.js program is to run the globally available node command (once you install Node.js) and pass the name of the file you want to execute. While running the command, make sure you are in the same directory which contains the app.js file.

Top Articles
Latest Posts
Article information

Author: Lidia Grady

Last Updated:

Views: 5834

Rating: 4.4 / 5 (45 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Lidia Grady

Birthday: 1992-01-22

Address: Suite 493 356 Dale Fall, New Wanda, RI 52485

Phone: +29914464387516

Job: Customer Engineer

Hobby: Cryptography, Writing, Dowsing, Stand-up comedy, Calligraphy, Web surfing, Ghost hunting

Introduction: My name is Lidia Grady, I am a thankful, fine, glamorous, lucky, lively, pleasant, shiny person who loves writing and wants to share my knowledge and understanding with you.