<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Omonigho Kenneth Jimmy</title>
    <description>The latest articles on Forem by Omonigho Kenneth Jimmy (@glitzyken).</description>
    <link>https://forem.com/glitzyken</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1035799%2F4b31f4b9-9fca-4c70-a206-2f023602d8e2.jpg</url>
      <title>Forem: Omonigho Kenneth Jimmy</title>
      <link>https://forem.com/glitzyken</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/glitzyken"/>
    <language>en</language>
    <item>
      <title>Security Best Practices for Your Node.js Application</title>
      <dc:creator>Omonigho Kenneth Jimmy</dc:creator>
      <pubDate>Wed, 17 Jul 2024 13:54:20 +0000</pubDate>
      <link>https://forem.com/appsignal/security-best-practices-for-your-nodejs-application-37ip</link>
      <guid>https://forem.com/appsignal/security-best-practices-for-your-nodejs-application-37ip</guid>
      <description>&lt;p&gt;The widespread adoption of Node.js continues to grow, making it a prime target for XSS, DoS, and brute force attacks. Therefore, protecting your Node application from possible vulnerabilities and threats is crucial.&lt;/p&gt;

&lt;p&gt;In this guide, we'll uncover common security threats and explore best practices for preventing them. You don't have to be a cybersecurity expert to implement fundamental security measures for your Node.js application.&lt;/p&gt;

&lt;p&gt;So, are you ready? Let's go! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Node.js Security Risks and Implementing Security Best Practices
&lt;/h2&gt;

&lt;p&gt;Let's explore the common security risks associated with Node.js applications and practical ways to mitigate them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threat: Injection Attacks (SQL, NoSQL)
&lt;/h3&gt;

&lt;p&gt;Sensitive data lives in your database. If an attacker inserts malicious queries or commands into input fields and finds their way in, they can gain unauthorized access to users' passwords, restricted data, or worse. This type of attack is known as SQL or NoSQL injection.&lt;/p&gt;

&lt;p&gt;For instance, suppose your application exposes an endpoint that accepts a movie category from a user input (through a query param):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.my-site.com/v1/movies?category=action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prompts the application to execute the following SQL query and fetch all released action movies from the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'action'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;isReleased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An attacker can construct an attack by injecting malicious SQL into the input like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.my-site.com/v1/movies?category=action'--
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in the following SQL query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'action'&lt;/span&gt;&lt;span class="c1"&gt;--' AND isReleased = true;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;--&lt;/code&gt; is a comment indicator in SQL, the rest of the statement after it, &lt;code&gt;AND isReleased = true&lt;/code&gt;, will be ignored. As a result, all movies are displayed, including those not yet released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mitigate Injection Attacks
&lt;/h2&gt;

&lt;p&gt;Let's now see what we can do to mitigate such attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use of Parameterized Queries
&lt;/h3&gt;

&lt;p&gt;Use parameterized queries instead of directly concatenating user input into the SQL query string. These techniques, also known as prepared statements, separate SQL logic from data, ensuring that user input is treated as a value rather than executable SQL code.&lt;/p&gt;

&lt;p&gt;For instance, based on the movie app example above, &lt;strong&gt;don't&lt;/strong&gt; process the user input like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mysql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// db credentials&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;
const query = `SELECT * FROM movies WHERE category = &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; AND isReleased = true`;

connection.query(query, (error, results, fields) =&amp;gt; {
  // handle results
});
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mysql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// db credentials&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;
const query = &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;FROM&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="nx"&gt;WHERE&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;AND&lt;/span&gt; &lt;span class="nx"&gt;isReleased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;

connection.query(query, [input], (error, results, fields) =&amp;gt; {
  // handle results
});
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second example uses a prepared statement, where the &lt;code&gt;?&lt;/code&gt; placeholder is the input value rather than a direct concatenation of the user input into the SQL query string (as shown in the first example). The user input is, therefore, passed separately as parameters to the prepared statement, preventing it from being interpreted as SQL code.&lt;/p&gt;

&lt;p&gt;It's noteworthy that while prepared statements can handle &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;number&lt;/code&gt; values effectively, they cannot and should not be used to parameterize table names, column names, SQL keywords, or other structural components of an SQL statement. If we have to make our query more dynamic, adding operators and identifiers as well as values, we should use other strategies like &lt;em&gt;whitelisting&lt;/em&gt;. This implies that every dynamic parameter should be manually set in your script and selected from that predefined set.&lt;/p&gt;

&lt;p&gt;For instance, suppose you want to add &lt;code&gt;ORDER BY&lt;/code&gt; dynamically into your SQL query. You can whitelist a set of allowed parameters and match the user input against this whitelist before constructing the query like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quantity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// whitelisted columns; you may use a hash map&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; UNION SELECT username, password FROM users--&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// malicious input&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid input!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`SELECT * FROM movies ORDER BY &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This technique ensures that the query only utilizes valid and anticipated identifiers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sanitize User Input
&lt;/h3&gt;

&lt;p&gt;Sanitizing input against database injection attacks involves removing or escaping keywords and characters that could be interpreted as part of an SQL/NoSQL query. Unsanitized user input is risky because, as demonstrated in the movie app example, attackers can leverage it to send malicious queries through your application to your database and steal important data.&lt;/p&gt;

&lt;p&gt;There are several known npm packages available for sanitizing SQL/NoSQL queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/sqlstring" rel="noopener noreferrer"&gt;sqlstring&lt;/a&gt; provides utility functions for escaping and formatting MySQL. For example, it provides methods like &lt;code&gt;escape()&lt;/code&gt;, which replaces special characters within the given input string with escape characters to ensure they are treated as literal values rather than parts of the SQL syntax.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/pg-format" rel="noopener noreferrer"&gt;pg-format&lt;/a&gt; formats SQL queries in PostgreSQL applications and provides functionality similar to that of sqlstring.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/express-mongo-sanitize" rel="noopener noreferrer"&gt;express-mongo-sanitize&lt;/a&gt; is popularly used in &lt;a href="https://www.mongodb.com" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt; applications to prevent Operator Injection. It works by analyzing request data and removing any MongoDB operators or characters such as &lt;code&gt;$gt&lt;/code&gt;, &lt;code&gt;$lt&lt;/code&gt;, &lt;code&gt;$eq&lt;/code&gt;, &lt;code&gt;$ne&lt;/code&gt;, &lt;code&gt;$regex&lt;/code&gt;, &lt;code&gt;$where&lt;/code&gt;, and others that could potentially be used to execute malicious queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use of ORMs/ODMs
&lt;/h3&gt;

&lt;p&gt;If your application doesn't necessitate raw SQL/NoSQL, opt for Object-Relational Mappers (ORMs) like &lt;a href="https://sequelize.org" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt; or Object-Document Mappers (ODMs) like &lt;a href="https://mongoosejs.com" rel="noopener noreferrer"&gt;Mongoose&lt;/a&gt; for database queries. They feature built-in protection against injection attacks, such as parameterized queries, automatic escaping, and schema validation, and adhere to some security best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threat: Cross-site Scripting (XSS)
&lt;/h3&gt;

&lt;p&gt;Using an input field, an attacker can store a malicious script (typically written in JavaScript) in your database through your Node.js app. The script is then served to multiple users whenever they access the affected web page or resource, and then executed in the victim's browser. This allows the attacker to steal sensitive information, manipulate web page content, or perform unauthorized actions on behalf of the user. This type of attack is known as cross-site scripting.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Prevent Cross-site Scripting
&lt;/h3&gt;

&lt;p&gt;We'll now turn to how we can avoid cross-site scripting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate User Input
&lt;/h3&gt;

&lt;p&gt;Validate all user-supplied input to ensure that it conforms to expected formats and does not contain malicious code. Use libraries like &lt;a href="https://www.npmjs.com/package/joi" rel="noopener noreferrer"&gt;joi&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/class-validator" rel="noopener noreferrer"&gt;class-validator&lt;/a&gt; for data validation.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a value is expected to be numeric, validate that it's numeric, and likewise for other data types.&lt;/li&gt;
&lt;li&gt;If a user submits a URL that you intend to include in responses, validate that it starts with a secure protocol, like HTTP or HTTPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Output Encoding
&lt;/h3&gt;

&lt;p&gt;Encode output data before user-controllable data is written to a page to prevent it from being interpreted as HTML or JavaScript. You can use tools like &lt;a href="https://www.npmjs.com/package/xss" rel="noopener noreferrer"&gt;xss&lt;/a&gt; for this purpose.&lt;/p&gt;

&lt;p&gt;In an HTML context, you should use HTML entities like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt; converts to &amp;amp;lt; &amp;gt; converts to &amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a JavaScript string context, non-alphanumeric values should be Unicode-escaped:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt; converts to \u003c
&amp;gt; converts to \u003e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use of &lt;code&gt;HTTPOnly&lt;/code&gt; Cookies
&lt;/h3&gt;

&lt;p&gt;If using cookies, set the &lt;code&gt;HTTPOnly&lt;/code&gt; flag to prevent access from client-side JavaScript. You can also use the &lt;code&gt;secure&lt;/code&gt; flag to ensure that cookies are only sent over HTTPS connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting HTTP Headers
&lt;/h3&gt;

&lt;p&gt;Setting special headers in your Node.js application is essential for controlling access and ensuring data integrity, thereby enhancing protection against XSS attacks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use libraries such as &lt;a href="https://www.npmjs.com/package/helmet" rel="noopener noreferrer"&gt;helmet&lt;/a&gt; to set special HTTP headers, like &lt;code&gt;X-XSS-Protection&lt;/code&gt; for mitigating XSS attacks.&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;Content-Disposition&lt;/code&gt; header to an attachment for file downloads to prevent browsers from executing downloaded files as scripts or HTML content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Threat: Brute Force
&lt;/h3&gt;

&lt;p&gt;What would you do if you wanted to unlock a phone but didn't know the password? You might try multiple combinations, but how many combinations can you make in a day if that would take hundreds, thousands, or even millions of guesses?&lt;/p&gt;

&lt;p&gt;What does it take to pull this off in minutes? Brute force. This type of attack is a forceful and repetitive trial-and-error method used to guess all possible combinations of a password, encryption key, or any other login information to gain unauthorized access.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Mitigate Brute Force
&lt;/h3&gt;

&lt;p&gt;Here's how we can help prevent brute-force attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate Limiting
&lt;/h3&gt;

&lt;p&gt;Use middleware or third-party packages such as &lt;a href="https://www.npmjs.com/package/express-rate-limit" rel="noopener noreferrer"&gt;express-rate-limit&lt;/a&gt; to enforce rate limits and restrict the number of API calls from a single IP address within a specific time frame.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application of Maximum Login Attempts
&lt;/h3&gt;

&lt;p&gt;Implement maximum login attempts and enforce account lockout when the threshold is exceeded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application of Multi-Factor Authentication (MFA)
&lt;/h3&gt;

&lt;p&gt;Implement Multi-Factor Authentication (MFA). Require users to provide a second form of authentication, such as a one-time passcode sent via SMS or email, in addition to their password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threat: Cross-Site Request Forgery (CSRF)
&lt;/h3&gt;

&lt;p&gt;An attacker could build a webpage form that creates a request against your site like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://my-vulnerable-site.com/email/change"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"user@evil-site.com"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose a user visits the attacker's page and is logged in to your site, assuming that your site uses a session cookie for authentication. In that case, their browser automatically includes their session cookie in the request.&lt;/p&gt;

&lt;p&gt;The vulnerable website will process the request in the normal way, treating it as though it had been made by the user, and proceed to change their email address.&lt;/p&gt;

&lt;p&gt;Subsequently, the attacker can change the user's password and gain access to the user's account. This type of attack — enabling an attacker to manipulate users into executing unintended actions — is known as Cross-Site Request Forgery (CSRF).&lt;/p&gt;

&lt;h3&gt;
  
  
  Mitigating CSRF Attacks
&lt;/h3&gt;

&lt;p&gt;The strongest defense against CSRF attacks is incorporating a CSRF token into relevant requests. The CSRF token strategy usually works like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server sends the client a token.&lt;/li&gt;
&lt;li&gt;The client submits a form with the token.&lt;/li&gt;
&lt;li&gt;The server rejects the request if the token is invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The token must meet the following criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unpredictable and possessing high complexity, much like session tokens in general.&lt;/li&gt;
&lt;li&gt;Associated with the user's session.&lt;/li&gt;
&lt;li&gt;Thoroughly verified before executing the relevant action in each case.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You could create a custom CSRF middleware leveraging package like &lt;a href="https://www.npmjs.com/package/csrf" rel="noopener noreferrer"&gt;csrf&lt;/a&gt; for generating and validating CSRF tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threat: Insecure Dependencies
&lt;/h3&gt;

&lt;p&gt;Let's face it, most Node.js applications need third-party libraries from npm or yarn for ease and speed of development. Sadly, this convenience comes with the risk of introducing unknown vulnerabilities to your application. (Granted, most maintainers address vulnerabilities in their packages and regularly release updated versions.)&lt;/p&gt;

&lt;p&gt;Here are some steps you can take to try to avoid introducing insecure dependencies into your application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constantly Update Your Dependencies
&lt;/h3&gt;

&lt;p&gt;You could use &lt;code&gt;npm audit&lt;/code&gt; or &lt;a href="https://www.npmjs.com/package/snyk" rel="noopener noreferrer"&gt;snyk&lt;/a&gt; to analyze your project’s dependencies tree and provide insights into any known vulnerabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify Packages Before Use
&lt;/h3&gt;

&lt;p&gt;Before integrating a library into your code, ensure it is stable and actively maintained, and review GitHub issues for that package. Additionally, examine its dependencies, reputation, reviews, and community support to guarantee the security and safety of your application. While these efforts can be demanding, they are essential to ensure the integrity of your integrated packages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Security Best Practices
&lt;/h3&gt;

&lt;p&gt;Let's end with a few other general best practices to keep your Node app secure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging and Monitoring
&lt;/h3&gt;

&lt;p&gt;Providing visibility into system activities can enhance security best practices. I highly recommend using AppSignal to &lt;a href="https://www.appsignal.com/tour/log-management" rel="noopener noreferrer"&gt;log&lt;/a&gt; and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;monitor your Node.js application&lt;/a&gt; because it is efficient and easy to integrate.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out my previous post on &lt;a href="https://blog.appsignal.com/2023/05/17/an-introduction-to-async-stack-traces-in-nodejs.html" rel="noopener noreferrer"&gt;Async Stack Traces in Node.js&lt;/a&gt; where I demonstrated how to set up AppSignal for Express.js applications easily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How can logging and monitoring your system help? You'll gain insights into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unusual login attempts&lt;/li&gt;
&lt;li&gt;Unauthorized access&lt;/li&gt;
&lt;li&gt;Suspicious network traffic&lt;/li&gt;
&lt;li&gt;Data passing through a network (both tracking and analysis)&lt;/li&gt;
&lt;li&gt;Log entries&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Run Node.js As a Non-root User
&lt;/h3&gt;

&lt;p&gt;If your Node.js app operates with root user privileges, attackers can exploit any vulnerabilities, granting them full control over your machine. They could then carry out destructive actions against your application.&lt;/p&gt;

&lt;p&gt;So, whether your backend runs on a dedicated server or Docker container, avoid using root users for Node.js. Olivier Lalonde's insights in the post &lt;a href="https://syskall.com/dont-run-node-dot-js-as-root" rel="noopener noreferrer"&gt;Don't run Node.js as root!&lt;/a&gt; are noteworthy here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deny Access To JWT After A Password Reset
&lt;/h3&gt;

&lt;p&gt;If a user is alerted and responds to unfamiliar access into their account by changing their password, blacklist the JWT previously issued to the client to avoid further access by the unknown actor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't Expose Error Details In the Response Payload
&lt;/h3&gt;

&lt;p&gt;Never send &lt;code&gt;500&lt;/code&gt; error details to the client. Attackers can use that information to exploit the vulnerabilities in your application. Instead, send a generic message like "Something went wrong 😔".&lt;/p&gt;

&lt;h3&gt;
  
  
  Denial of Service (DoS)
&lt;/h3&gt;

&lt;p&gt;Mitigate DoS attacks by using rate limiters for network throttling and libraries such as &lt;a href="https://www.npmjs.com/package/body-parser" rel="noopener noreferrer"&gt;body-parser&lt;/a&gt; to limit body payload size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Using Default Cookie Names
&lt;/h3&gt;

&lt;p&gt;Don't use default names for cookies, as they might unintentionally disclose the technology stack your backend relies upon. By discerning the framework in use, attackers can exploit any particular vulnerabilities associated with it.&lt;/p&gt;

&lt;p&gt;Instead, opt for custom cookie names.&lt;/p&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we explored common security threats in Node.js applications and practical ways to mitigate them for production environments.&lt;/p&gt;

&lt;p&gt;You can fortify your applications against evolving security risks by implementing these security measures and remaining vigilant.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery" rel="noopener noreferrer"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
    </item>
    <item>
      <title>Job Schedulers for Node: Bull or Agenda?</title>
      <dc:creator>Omonigho Kenneth Jimmy</dc:creator>
      <pubDate>Wed, 13 Sep 2023 14:00:00 +0000</pubDate>
      <link>https://forem.com/appsignal/job-schedulers-for-node-bull-or-agenda-39n3</link>
      <guid>https://forem.com/appsignal/job-schedulers-for-node-bull-or-agenda-39n3</guid>
      <description>&lt;p&gt;Whether you're familiar with job schedulers or new to the concept, two popular libraries in the Node.js ecosystem stand out: Bull and Agenda.&lt;/p&gt;

&lt;p&gt;These libraries provide unique features and advantages when it comes to efficient job scheduling. Let's explore the ins and outs of Bull and Agenda! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling Jobs in Node.js: Conducting An Orchestra
&lt;/h2&gt;

&lt;p&gt;A job scheduler can be likened to &lt;strong&gt;an orchestra conductor&lt;/strong&gt; in a Node.js application. Just as a conductor leads and coordinates musicians to produce a harmonious symphony, a job scheduler orchestrates the execution of tasks in your application.&lt;/p&gt;

&lt;p&gt;Imagine your application as a grand orchestra, with each task representing a skilled musician. Without a conductor, each musician might play their part at their own pace, resulting in a disjointed and chaotic performance. Similarly, without a job scheduler, tasks in your application may run independently, leading to resource conflicts, delays, and suboptimal performance.&lt;/p&gt;

&lt;p&gt;Just as a conductor adapts to unforeseen circumstances during a live performance, a job scheduler handles exceptions and failures in your application. It gracefully manages errors, reschedules failed tasks, and ensures that the show goes on smoothly, maintaining the reliability and resilience of your application.&lt;/p&gt;

&lt;p&gt;Now that we've summarised the role of a job scheduler, let's turn our attention to what Bull can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bull for Node.js
&lt;/h2&gt;

&lt;p&gt;Bull claims to be the fastest, most reliable Redis-based queue for Node.js. It is known for its high performance, scalability, and robustness. With Bull, you can create queues to manage and process jobs asynchronously, making it ideal for handling time-consuming or resource-intensive tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Bull as a Job Scheduler
&lt;/h3&gt;

&lt;p&gt;Using Bull as a job scheduler brings several benefits to your Node.js application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High performance and scalability:&lt;/strong&gt; Bull leverages efficient algorithms and data structures to process jobs quickly. It is designed to handle high workloads and scales horizontally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliable job processing and job queues:&lt;/strong&gt; Bull ensures reliable job processing by providing features such as job persistence, automatic retries, error handling, and priority queues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced job scheduling options:&lt;/strong&gt; You can schedule jobs to run at specific times, set recurring jobs using cron-like expressions, or define intervals between job executions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring and insights:&lt;/strong&gt; Bull provides a built-in monitoring dashboard to track job progress, view statistics, and monitor performance metrics. This feature allows you to gain insights into the job processing pipeline, identify bottlenecks, and optimize your application's performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration and compatibility:&lt;/strong&gt; Bull integrates well with popular frameworks like Express or Nest.js and can easily integrate with different data stores, message brokers, and external services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensive ecosystem and community support:&lt;/strong&gt; Bull is actively maintained and regularly updated, ensuring compatibility with the latest versions of Node.js. The community provides helpful resources, documentation, and plugins to extend Bull's functionality and address various use cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take note, however, of the following information from the &lt;a href="https://github.com/OptimalBits/bull#-news-and-updates"&gt;Bull documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bull is currently in maintenance mode, we are only fixing bugs. For new features check &lt;a href="https://github.com/taskforcesh/bullmq"&gt;BullMQ&lt;/a&gt;, a modern rewritten implementation in Typescript. You are still very welcome to use Bull if it suits your needs, which is a safe, battle-tested library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Real-world Use Cases Where Bull Shines
&lt;/h3&gt;

&lt;p&gt;Bull excels in real-world use cases where efficient job scheduling and task management are critical. In &lt;strong&gt;distributed systems or microservice architectures&lt;/strong&gt;, Bull particularly shines as a job scheduler for coordinating and synchronizing tasks across multiple services or nodes. Here's a code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Service A - Producer&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bull&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create a Bull queue&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskQueue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Producer service adds jobs to the queue&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;addToQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Job added to the queue:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Service B - Consumer&lt;/span&gt;

&lt;span class="c1"&gt;// Create a Bull queue with the same name as the producer&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;taskQueue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Consumer service processes jobs from the queue&lt;/span&gt;
&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Processing job:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Perform the necessary actions for the job&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="c1"&gt;// Mark the job as completed&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start producing jobs&lt;/span&gt;
&lt;span class="nx"&gt;addToQueue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Task 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;addToQueue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Task 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;addToQueue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Task 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we have two services, Service A (Producer) and Service B (Consumer). They both share a Bull queue named &lt;code&gt;taskQueue&lt;/code&gt;. Service A produces jobs by adding data to the queue using the &lt;code&gt;addToQueue&lt;/code&gt; function. Service B consumes these jobs and processes them using the &lt;code&gt;queue.process&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;For instance, when &lt;code&gt;addToQueue({ data: 'Task 1' })&lt;/code&gt; is called, it adds a job to the Bull queue named &lt;code&gt;taskQueue&lt;/code&gt;. The job contains data &lt;code&gt;{ data: 'Task 1' }&lt;/code&gt; representing the specific task or job to be processed.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;queue.add(data)&lt;/code&gt; method adds the job to the queue, and Bull takes care of persisting the job details in the underlying Redis database. The job is then available for consumption by any connected consumer service processing jobs from the same queue.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;queue.process&lt;/code&gt; is called in the consumer service, it sets up a worker that listens to the queue and starts processing jobs as they become available. In this case, the worker will process the job containing &lt;code&gt;{ data: 'Task 1' }&lt;/code&gt; once it reaches the front of the queue.&lt;/p&gt;

&lt;p&gt;The job processing involves invoking the function provided to &lt;code&gt;queue.process&lt;/code&gt;. In the code example, the function logs the job data (&lt;code&gt;console.log('Processing job:', job.data)&lt;/code&gt;) and performs any necessary actions specific to the job.&lt;/p&gt;

&lt;p&gt;By calling &lt;code&gt;addToQueue&lt;/code&gt; with different data for each task, you can add multiple jobs to the queue. The consumer service will process them one by one based on the order in which they were added.&lt;/p&gt;

&lt;p&gt;Other use cases where Bull shines include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Background processing and task offloading&lt;/li&gt;
&lt;li&gt;Task scheduling and automation&lt;/li&gt;
&lt;li&gt;Job queues and workload balancing&lt;/li&gt;
&lt;li&gt;Delayed and retry mechanisms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, as the saying goes: "Every rose has its thorn". Bull, while an exciting choice of job scheduler, also has some noteworthy drawbacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential Drawbacks of Bull
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency on Redis:&lt;/strong&gt; Bull relies on Redis as its underlying data store, requiring the setup and maintenance of a Redis server. This can introduce added complexity and infrastructure demands if you're not already using Redis in your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Steep learning curve:&lt;/strong&gt; Bull's wide range of features and advanced options may require developers new to job scheduling and asynchronous task management to invest time in learning and experimenting to utilize its capabilities effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory consumption:&lt;/strong&gt; Bull's memory usage can increase with large job queues, necessitating careful monitoring and optimization to stay within acceptable limits, particularly in memory-constrained or high-throughput environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence options:&lt;/strong&gt; Bull's reliance on Redis for persistence may not align with your preferred data store, potentially necessitating custom solutions or alternative job scheduler libraries to integrate with a different database system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overkill for simple use cases:&lt;/strong&gt; If your application has straightforward scheduling requirements or doesn't require advanced job processing features, integrating Bull may introduce unnecessary complexity. In such cases, a simpler job scheduler or task queue solution might be more suitable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This brings us to Bull’s alternative — Agenda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agenda for Node.js
&lt;/h2&gt;

&lt;p&gt;Agenda is a lightweight job scheduling library for Node.js, built on top of MongoDB. It focuses on simplicity and ease of use, making it an excellent choice for applications that require basic job scheduling capabilities without the need for complex features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Agenda as a Job Scheduler
&lt;/h3&gt;

&lt;p&gt;Here are a few notable benefits of using Agenda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple and lightweight:&lt;/strong&gt; Agenda is designed to be lightweight and easy to use, making it a great choice for applications with simpler job scheduling requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence options:&lt;/strong&gt; Unlike Bull, Agenda supports multiple databases, including MongoDB as the default choice. This gives you the flexibility to use your preferred database system for storing job data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-driven architecture:&lt;/strong&gt; Agenda's event-driven architecture enables seamless integration and efficient communication between application components through custom event-triggered job execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error handling and job recovery:&lt;/strong&gt; Agenda includes built-in error handling, job recovery, retries, and concurrency control, ensuring effective management of job execution errors and recovery from failures in your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job scheduling flexibility:&lt;/strong&gt; Agenda provides comprehensive scheduling capabilities, human-readable syntax, and complex recurring schedules for executing tasks at regular intervals or specific times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active community and maintenance:&lt;/strong&gt; Agenda has an active community and ongoing maintenance, ensuring regular updates, bug fixes, ample resources, documentation, and community support for any issues or assistance you may need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Examples Where Agenda Is a Good Fit
&lt;/h3&gt;

&lt;p&gt;Agenda is well-suited for a range of scenarios, including recurring tasks, cron jobs, event-driven workflows, and lightweight use cases that demand a straightforward API and a minimalistic solution for job scheduling in your application.&lt;/p&gt;

&lt;p&gt;The following piece of code uses Agenda to execute tasks based on complex time patterns (using cron syntax):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Agenda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agenda&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agenda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Agenda&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Define a job to be executed based on cron schedule&lt;/span&gt;
&lt;span class="nx"&gt;agenda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sendEmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Send email logic here&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Sending email to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; with subject: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Define the cron schedule for the job&lt;/span&gt;
&lt;span class="nx"&gt;agenda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 8 * * *&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sendEmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Daily Report&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, this is your daily report.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start the agenda instance and execute jobs&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agenda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Agenda started&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Optionally, you can define additional jobs and schedules here&lt;/span&gt;

  &lt;span class="c1"&gt;// Gracefully shut down the agenda instance&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agenda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we define an Agenda instance and then define a job named &lt;code&gt;sendEmail&lt;/code&gt;. We specify the job's logic inside the async function. The &lt;code&gt;every&lt;/code&gt; method is used to schedule the job with the cron expression &lt;code&gt;0 8 * * *&lt;/code&gt;, which means that the job will run every day at 8:00 AM. The job data includes the email recipient, subject, and body.&lt;/p&gt;

&lt;p&gt;When the agenda starts, it will execute the job according to the defined schedule. You can add more jobs and schedules as needed within the async block. Finally, the optional &lt;code&gt;await agenda.stop();&lt;/code&gt; is called to gracefully stop the Agenda instance when the application is finished.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations of Agenda
&lt;/h3&gt;

&lt;p&gt;While Agenda offers several advantages, it also comes with some trade-offs to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lack of advanced features:&lt;/strong&gt; If your application requires complex job orchestration, prioritization, or extensive queue management, you may find Agenda's feature set to be less comprehensive than Bull's.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single process execution:&lt;/strong&gt; By default, Agenda operates within a single process, which simplifies deployment and setup but may not scale as effectively as Bull in terms of handling high job concurrency and distributed processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less active community:&lt;/strong&gt; While Agenda has an active community, it may have a smaller user base compared to other popular alternatives like Bull, potentially resulting in fewer available resources, documentation, and community support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning curve for complex scenarios:&lt;/strong&gt; Agenda is user-friendly for simpler use cases, but can have a steeper learning curve for complex job scheduling needs. If your application requires intricate workflows, advanced scheduling patterns, or sophisticated error handling, a deeper understanding of Agenda's capabilities may be necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Feature Comparison between Bull and Agenda for Node.js
&lt;/h3&gt;

&lt;p&gt;Here's a concise table comparing the features of each library to help you choose the optimal job scheduler for your Node.js projects.&lt;/p&gt;

&lt;p&gt;Let's dive into the key similarities and differences between Bull and Agenda to make an informed choice! 🚀&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;🐂 Bull&lt;/th&gt;
&lt;th&gt;🗓️ Agenda&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Job Persistence&lt;/td&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;MongoDB (with support for other databases)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Suitable for high job concurrency&lt;/td&gt;
&lt;td&gt;Single process, may not scale as effectively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Relatively easy for simpler use cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced Features&lt;/td&gt;
&lt;td&gt;Extensive options for job management&lt;/td&gt;
&lt;td&gt;Limited compared to more feature-rich schedulers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistence Flexibility&lt;/td&gt;
&lt;td&gt;Tightly integrated with Redis&lt;/td&gt;
&lt;td&gt;Supports multiple databases, including MongoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event-Driven Architecture&lt;/td&gt;
&lt;td&gt;Not emphasized&lt;/td&gt;
&lt;td&gt;Embraces event-driven workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error Handling&lt;/td&gt;
&lt;td&gt;Customizable error-handling mechanisms&lt;/td&gt;
&lt;td&gt;Built-in error handling and job recovery options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community Support&lt;/td&gt;
&lt;td&gt;Widely adopted, active community&lt;/td&gt;
&lt;td&gt;Active community but with a smaller user base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduling Flexibility&lt;/td&gt;
&lt;td&gt;Versatile scheduling options&lt;/td&gt;
&lt;td&gt;Rich set of scheduling features, including cron&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource Consumption&lt;/td&gt;
&lt;td&gt;Potentially higher memory consumption&lt;/td&gt;
&lt;td&gt;Lightweight and optimized for lower resource usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration&lt;/td&gt;
&lt;td&gt;Works well with existing Redis setups&lt;/td&gt;
&lt;td&gt;Flexible integration with various tech stacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Case Suitability&lt;/td&gt;
&lt;td&gt;Complex job orchestration and queueing&lt;/td&gt;
&lt;td&gt;Simpler use cases and straightforward scheduling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ultimately, the choice between Bull and Agenda boils down to your project's specific needs and complexity. Whether you prioritize advanced features, scalability, simplicity, or specific integration requirements, use the insights gained from this comparison to make an informed decision that aligns with your development goals.&lt;/p&gt;

&lt;p&gt;Remember, your choice of job scheduler plays a vital role in efficient task management. Choose wisely and enjoy seamless job scheduling in your Node.js applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we explored Bull and Agenda as job scheduler libraries for Node.js applications.&lt;/p&gt;

&lt;p&gt;We learned about the benefits of Bull, such as reliable job persistence and extensive features, and its real-world use cases. Additionally, we discovered Agenda's advantages, including its support for multiple databases, event-driven architecture, and rich scheduling options.&lt;/p&gt;

&lt;p&gt;By comparing their features, potential drawbacks, and use case suitability, we can now make informed decisions when choosing between Bull and Agenda for our specific application requirements.&lt;/p&gt;

&lt;p&gt;Happy job scheduling!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
    </item>
    <item>
      <title>An Introduction to Async Stack Traces in Node.js</title>
      <dc:creator>Omonigho Kenneth Jimmy</dc:creator>
      <pubDate>Wed, 24 May 2023 11:19:30 +0000</pubDate>
      <link>https://forem.com/appsignal/an-introduction-to-async-stack-traces-in-nodejs-4cn4</link>
      <guid>https://forem.com/appsignal/an-introduction-to-async-stack-traces-in-nodejs-4cn4</guid>
      <description>&lt;p&gt;Node.js 12.x onwards introduced async stack traces. Async stack traces allow developers to view the call stack of asynchronous code, making it easier to trace and debug code issues.&lt;/p&gt;

&lt;p&gt;In this post, we’ll see how async stack traces work, how you can use them to debug code, and how to track them using AppSignal. Ready?&lt;/p&gt;

&lt;p&gt;Let's get going!&lt;/p&gt;

&lt;h2&gt;
  
  
  How Async Stack Traces Work in Node.js
&lt;/h2&gt;

&lt;p&gt;In JavaScript, asynchronous code is executed through callbacks, promises, and async/await. When an error occurs in asynchronous code, it can be difficult to trace its origin because the call stack is not captured at the point of the error. Async stack traces capture the call stack when the asynchronous code is scheduled rather than when it is executed, allowing developers to see an error's full context.&lt;/p&gt;

&lt;p&gt;Node.js uses an event-driven, non-blocking I/O model for handling asynchronous code execution. An event loop constantly checks for new tasks, executes them one by one, and registers callback functions for tasks that do not block the execution. This allows Node.js to handle multiple tasks simultaneously, improving performance and scalability.&lt;/p&gt;

&lt;p&gt;Async stack traces capture the call stack when an async operation begins using "long stack traces". When an async operation starts, Node.js creates a new execution context that includes information about the current call stack and the location where the async operation was initiated. This execution context is then passed along with the async operation as it is scheduled and executed.&lt;/p&gt;

&lt;p&gt;When an error occurs, Node.js can reference the execution context to determine the entire call stack at the point where the async operation began. It enriches the stack property of &lt;code&gt;Error&lt;/code&gt; instances with async stack frames, i.e., await locations in the code. These async frames are marked with &lt;code&gt;async&lt;/code&gt; in the stack string. You can see the full context of an error, including the function calls and variables that led to the error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node.js Async Stack Traces: A Code Example
&lt;/h2&gt;

&lt;p&gt;Consider the following code. An async function &lt;code&gt;init()&lt;/code&gt; calls &lt;code&gt;funcOne()&lt;/code&gt;, which then calls &lt;code&gt;funcTwo()&lt;/code&gt;, which then calls and throws &lt;code&gt;funcThree()&lt;/code&gt;. Async stack traces will print a stack trace with &lt;code&gt;init()&lt;/code&gt;, &lt;code&gt;funcOne()&lt;/code&gt;, &lt;code&gt;funcTwo()&lt;/code&gt;, and &lt;code&gt;funcThree()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;funcThree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oops&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;funcTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;funcThree&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;funcOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;funcTwo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;funcOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in an output like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node ./asyncStackTraces.js

Error: Oops
    at funcThree &lt;span class="o"&gt;(&lt;/span&gt;/Users/kennethjimmy/Desktop/asyncStackTraces.js:3:9&lt;span class="o"&gt;)&lt;/span&gt;
    at async funcTwo &lt;span class="o"&gt;(&lt;/span&gt;/Users/kennethjimmy/Desktop/asyncStackTraces.js:8:3&lt;span class="o"&gt;)&lt;/span&gt;
    at async funcOne &lt;span class="o"&gt;(&lt;/span&gt;/Users/kennethjimmy/Desktop/asyncStackTraces.js:13:3&lt;span class="o"&gt;)&lt;/span&gt;
    at async init &lt;span class="o"&gt;(&lt;/span&gt;/Users/kennethjimmy/Desktop/asyncStackTraces.js:18:3&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run the same code on a version of Node.js older than 12, the output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node ./asyncStackTraces.js

Error: Oops
    at funcThree &lt;span class="o"&gt;(&lt;/span&gt;/Users/kennethjimmy/Desktop/asyncStackTraces.js:3:9&lt;span class="o"&gt;)&lt;/span&gt;
    at &amp;lt;anonymous&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;at &amp;lt;anonymous&amp;gt;&lt;/code&gt; isn’t very helpful in revealing the full context of the error.&lt;/p&gt;

&lt;p&gt;However, this works differently with async stack traces. When an error occurs in a callback function, the call stack is captured at the point when a callback is scheduled (the &lt;code&gt;init()&lt;/code&gt; function in this case), rather than when it is executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up AppSignal for Your Express.js App
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.appsignal.com/nodejs"&gt;AppSignal&lt;/a&gt; can assist you in identifying and troubleshooting problems with your app, including issues related to slow performance, errors, crashes, and downtime. You can resolve these issues quickly before they negatively impact your users.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will walk you through how to &lt;a href="https://www.appsignal.com/nodejs/express-js-performance-monitoring"&gt;integrate AppSignal into your Express.js app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: &lt;a href="https://github.com/Glitzyken/async-stack-traces-appSignal"&gt;You can follow along with the source code for the following tutorial here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Firstly, &lt;a href="https://appsignal.com/users/sign_up"&gt;sign up for an account on appsignal.com&lt;/a&gt; and create a new app by following &lt;a href="https://docs.appsignal.com/guides"&gt;these guides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then start a new Node.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install AppSignal for Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @appsignal/nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your repo’s root directory, create an &lt;code&gt;appsignal.cjs&lt;/code&gt; file and paste the following code to require and configure AppSignal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Appsignal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@appsignal/nodejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Appsignal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPSIGNAL_APP_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pushApiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPSIGNAL_PUSH_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Note: renamed from `apiKey` in version 2.2.5&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: An application's Push API key is given during setup and can be found in the App settings &amp;gt; Push &amp;amp; deploy tab.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;package.json&lt;/code&gt; file, edit the &lt;code&gt;start&lt;/code&gt; script to load AppSignal's configuration before any other library using the &lt;code&gt;--require&lt;/code&gt; flag, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node --require ‘./appsignal.cjs’ app.mjs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integrating AppSignal into your Express app is very easy. You just need to require the &lt;code&gt;expressErrorHandler&lt;/code&gt; module and then use it in your app with &lt;code&gt;app.use&lt;/code&gt;, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expressErrorHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@appsignal/nodejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// add this after all routes, but before any other error handlers&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expressErrorHandler&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;expressErrorHandler&lt;/code&gt; module consists of middleware designed to forward any errors in your Express application to AppSignal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking Async Callback Errors with AppSignal
&lt;/h2&gt;

&lt;p&gt;Let's create an error inside an asynchronous callback to see how AppSignal handles it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;funcThree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oops&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;funcTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;funcThree&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;funcOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;funcTwo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/trigger_error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;catchAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;funcOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;statusbar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;mentors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When accessing &lt;code&gt;GET /trigger_error&lt;/code&gt;, an error is triggered. The server will return the error along with an asynchronous stack trace, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"error"&lt;/span&gt;,
  &lt;span class="s2"&gt;"error"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"statusCode"&lt;/span&gt;: 500,
      &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"error"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="s2"&gt;"message"&lt;/span&gt;: &lt;span class="s2"&gt;"Oops"&lt;/span&gt;,
  &lt;span class="s2"&gt;"stack"&lt;/span&gt;: &lt;span class="s2"&gt;"Error: Oops&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at funcThree (file:///Users/kennethjimmy/Desktop/app.mjs:29:9)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at async funcTwo (file:///Users/kennethjimmy/Desktop/app.mjs:34:3)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at async funcOne (file:///Users/kennethjimmy/Desktop/app.mjs:39:3)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at async file:///Users/kennethjimmy/Desktop/app.mjs:55:5"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the error is thrown, AppSignal captures and reports the exception. To view your application's errors and stack traces, navigate to the AppSignal Dashboard, select "Errors", and click on "Issue list."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wFT6Sn9J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-05/error-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wFT6Sn9J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-05/error-list.png" alt="Error list" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on a particular error to see its details, including the error message and stack trace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F5TKm1Ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-05/error-message.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F5TKm1Ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-05/error-message.png" alt="Error message" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Increasing Stack Trace Size in Node.js
&lt;/h2&gt;

&lt;p&gt;By default, stack trace size is limited, making it difficult to pinpoint the exact source of an error. In development, we want as much context as we can get. Fortunately, it's possible to increase stack trace size in Node.js.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;code&gt;stackTraceLimit&lt;/code&gt; property of the &lt;code&gt;Error&lt;/code&gt; object/class. By default, this property is set to 10, so only the last 10 calls will be included in the stack trace. If the value is set to 0, this stops the collection of stack traces. However, any positive integer can be assigned as the maximum limit for collecting frames. Alternatively, setting the property to &lt;code&gt;Infinity&lt;/code&gt; will collect all the frames.&lt;/p&gt;

&lt;p&gt;For example, to set the stack trace limit to &lt;code&gt;Infinity&lt;/code&gt; in an Express.js application in development mode, you can use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// Set the stack trace limit to Infinity &lt;span class="k"&gt;in &lt;/span&gt;development mode
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;process.env.NODE_ENV &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s1"&gt;'production'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  Error.stackTraceLimit &lt;span class="o"&gt;=&lt;/span&gt; Infinity
&lt;span class="o"&gt;}&lt;/span&gt;

// Initialize Express.js app
const express &lt;span class="o"&gt;=&lt;/span&gt; require&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'express'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
const app &lt;span class="o"&gt;=&lt;/span&gt; express&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

// Define routes
// ...

// Start the server
const port &lt;span class="o"&gt;=&lt;/span&gt; process.env.PORT &lt;span class="o"&gt;||&lt;/span&gt; 3000&lt;span class="p"&gt;;&lt;/span&gt;
app.listen&lt;span class="o"&gt;(&lt;/span&gt;port, &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  console.log&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;Server started on port &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By increasing stack trace size, you can get more information about the execution of your code and better understand the context in which an error occurs. However, it's important to consider the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance impact:&lt;/strong&gt; Increasing stack trace size can negatively impact performance, particularly in cases where a large number of errors occur, or the stack trace size is set to an excessively high value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory usage:&lt;/strong&gt; A larger stack trace size means more memory usage, which can be a concern if your application is already memory-intensive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security risks:&lt;/strong&gt; Longer stack traces can potentially expose sensitive information, such as credentials or source code, if not properly handled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity:&lt;/strong&gt; It can be more difficult to navigate and analyze a larger stack trace, particularly for complex applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that in mind, you should use a reasonable limit that provides the necessary information without causing performance issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we've seen how async stack traces in Node.js can help you debug and trace errors in your asynchronous code by capturing call stacks.&lt;/p&gt;

&lt;p&gt;We also explored how integrating AppSignal into your Node.js application makes it a lot easier to detect and resolve async callback errors in real time.&lt;/p&gt;

&lt;p&gt;Finally, we discussed how expanding stack trace size in Node.js can offer more insights into the execution of your code and help you understand an error's context. However, it's important to use this feature judiciously, taking into account its possible impact on performance, memory usage, security, and navigability.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
