diff --git a/.operations/.markdownlint.json b/.operations/.markdownlint.json index 1b7cc1d58..6ae384f15 100644 --- a/.operations/.markdownlint.json +++ b/.operations/.markdownlint.json @@ -2,6 +2,6 @@ "default": true, "MD033": false, "MD001": false, - "MD013": {"line_length": 150}, + "MD013": false, "MD039": false } \ No newline at end of file diff --git a/README.md b/README.md index 0ef44db2b..ceec4ea26 100644 --- a/README.md +++ b/README.md @@ -9,29 +9,16 @@
- 84 items - Last update: Jun 5, 2019 - Updated for Node 12.14.0 LTS + 84 items Last update: Jun 5, 2019 Updated for Node 12.14.0 LTS

-[![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) -**Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/) +[![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)
-Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), - [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md) - [(![ES](/assets/flags/ES.png)**ES**, - ![FR](/assets/flags/FR.png)**FR**, - ![HE](/assets/flags/HE.png)**HE**, - ![KR](/assets/flags/KR.png)**KR**, - ![RU](/assets/flags/RU.png)**RU** and - ![TR](/assets/flags/TR.png)**TR** in progress!)](#translations) +Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR**, ![RU](/assets/flags/RU.png)**RU** and ![TR](/assets/flags/TR.png)**TR** in progress!)](#translations)
@@ -43,22 +30,17 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines - **We seek typescript contributors:** want to help contributing TypeScript examples? please approach by opening an issue -- **New translation:** ![BR](/assets/flags/BR.png) [Brazilian Portuguese](/README.brazilian-portuguese.md) available now, -courtesy of [Marcelo Melo](https://github.com/marcelosdm)! ❤️ +- **New translation:** ![BR](/assets/flags/BR.png) [Brazilian Portuguese](/README.brazilian-portuguese.md) available now, courtesy of [Marcelo Melo](https://github.com/marcelosdm)! ❤️

# Welcome! 3 Things You Ought To Know First -**1. You are, in fact, reading dozens of the best Node.js articles -** this repository is a summary and curation of the -top-ranked content on Node.js best practices, as well as content written here by collaborators +**1. You are, in fact, reading dozens of the best Node.js articles -** this repository is a summary and curation of the top-ranked content on Node.js best practices, as well as content written here by collaborators -**2. It is the largest compilation, and it is growing every week -** currently, more than 80 best practices, style guides, and architectural tips are presented. -New issues and pull requests are created every day to keep this live book updated. We'd love to see you contributing here, -whether that is fixing code mistakes, helping with translations, or suggesting brilliant new ideas. See our [writing guidelines here](/.operations/writing-guidelines.md) +**2. It is the largest compilation, and it is growing every week -** currently, more than 80 best practices, style guides, and architectural tips are presented. New issues and pull requests are created every day to keep this live book updated. We'd love to see you contributing here, whether that is fixing code mistakes, helping with translations, or suggesting brilliant new ideas. See our [writing guidelines here](/.operations/writing-guidelines.md) -**3. Most best practices have additional info -** most bullets include a **🔗Read More** link that expands on the practice -with code examples, quotes from selected blogs and more information +**3. Most best practices have additional info -** most bullets include a **🔗Read More** link that expands on the practice with code examples, quotes from selected blogs and more information

@@ -78,14 +60,9 @@ with code examples, quotes from selected blogs and more information ## ![✔] 1.1 Structure your solution by components -**TL;DR:** The worst large applications pitfall is maintaining a huge code base with hundreds of dependencies - such a -monolith slows down developers as they try to incorporate new features. Instead, partition your code into components, each -gets its own folder or a dedicated codebase, and ensure that each unit is kept small and simple. Visit 'Read More' below to -see examples of correct project structure +**TL;DR:** The worst large applications pitfall is maintaining a huge code base with hundreds of dependencies - such a monolith slows down developers as they try to incorporate new features. Instead, partition your code into components, each gets its own folder or a dedicated codebase, and ensure that each unit is kept small and simple. Visit 'Read More' below to see examples of correct project structure -**Otherwise:** When developers who code new features struggle to realize the impact of their change and fear to break other -dependent components - deployments become slower and riskier. It's also considered harder to scale-out when all the business -units are not separated +**Otherwise:** When developers who code new features struggle to realize the impact of their change and fear to break other dependent components - deployments become slower and riskier. It's also considered harder to scale-out when all the business units are not separated 🔗 [**Read More: structure by components**](/sections/projectstructre/breakintcomponents.md) @@ -93,10 +70,7 @@ units are not separated ## ![✔] 1.2 Layer your components, keep Express within its boundaries -**TL;DR:** Each component should contain 'layers' - a dedicated object for the web, logic, and data access code. This not only -draws a clean separation of concerns but also significantly eases mocking and testing the system. Though this is a very common -pattern, API developers tend to mix layers by passing the web layer objects (Express req, res) to business logic and data -layers - this makes your application dependent on and accessible by Express only +**TL;DR:** Each component should contain 'layers' - a dedicated object for the web, logic, and data access code. This not only draws a clean separation of concerns but also significantly eases mocking and testing the system. Though this is a very common pattern, API developers tend to mix layers by passing the web layer objects (Express req, res) to business logic and data layers - this makes your application dependent on and accessible by Express only **Otherwise:** App that mixes web objects with other layers cannot be accessed by testing code, CRON jobs, and other non-Express callers @@ -106,9 +80,7 @@ layers - this makes your application dependent on and accessible by Express only ## ![✔] 1.3 Wrap common utilities as npm packages -**TL;DR:** In a large app that constitutes a large code base, cross-cutting-concern utilities like logger, encryption and -alike, should be wrapped by your own code and exposed as private npm packages. This allows sharing them among multiple code -bases and projects +**TL;DR:** In a large app that constitutes a large code base, cross-cutting-concern utilities like logger, encryption and alike, should be wrapped by your own code and exposed as private npm packages. This allows sharing them among multiple code bases and projects **Otherwise:** You'll have to invent your own deployment and dependency wheel @@ -118,12 +90,9 @@ bases and projects ## ![✔] 1.4 Separate Express 'app' and 'server' -**TL;DR:** Avoid the nasty habit of defining the entire [Express](https://expressjs.com/) app in a single huge file - separate -your 'Express' definition to at least two files: the API declaration (app.js) and the networking concerns (WWW). For even -better structure, locate your API declaration within components +**TL;DR:** Avoid the nasty habit of defining the entire [Express](https://expressjs.com/) app in a single huge file - separate your 'Express' definition to at least two files: the API declaration (app.js) and the networking concerns (WWW). For even better structure, locate your API declaration within components -**Otherwise:** Your API will be accessible for testing via HTTP calls only (slower and much harder to generate coverage -reports). It probably won't be a big pleasure to maintain hundreds of lines of code in a single file +**Otherwise:** Your API will be accessible for testing via HTTP calls only (slower and much harder to generate coverage reports). It probably won't be a big pleasure to maintain hundreds of lines of code in a single file 🔗 [**Read More: separate Express 'app' and 'server'**](/sections/projectstructre/separateexpress.md) @@ -131,9 +100,7 @@ reports). It probably won't be a big pleasure to maintain hundreds of lines of c ## ![✔] 1.5 Use environment aware, secure and hierarchical config -**TL;DR:** A perfect and flawless configuration setup should ensure (a) keys can be read from file AND from environment -variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability. There are a few -packages that can help tick most of those boxes like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf) and [config](https://www.npmjs.com/package/config) +**TL;DR:** A perfect and flawless configuration setup should ensure (a) keys can be read from file AND from environment variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability. There are a few packages that can help tick most of those boxes like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf) and [config](https://www.npmjs.com/package/config) **Otherwise:** Failing to satisfy any of the config requirements will simply bog down the development or devops team. Probably both @@ -147,12 +114,9 @@ packages that can help tick most of those boxes like [rc](https://www.npmjs.com/ ## ![✔] 2.1 Use Async-Await or promises for async error handling -**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best -gift you can give to your code is using a reputable promise library or async-await instead which enables a much more compact -and familiar code syntax like try-catch +**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using a reputable promise library or async-await instead which enables a much more compact and familiar code syntax like try-catch -**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of -error handling with casual code, excessive nesting, and awkward coding patterns +**Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting, and awkward coding patterns 🔗 [**Read More: avoiding callbacks**](/sections/errorhandling/asyncerrorhandling.md) @@ -160,12 +124,9 @@ error handling with casual code, excessive nesting, and awkward coding patterns ## ![✔] 2.2 Use only the built-in Error object -**TL;DR:** Many throw errors as a string or as some custom type – this complicates the error handling logic and the -interoperability between modules. Whether you reject a promise, throw an exception or emit an error – using only the built-in -Error object will increase uniformity and prevent loss of information +**TL;DR:** Many throw errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Whether you reject a promise, throw an exception or emit an error – using only the built-in Error object will increase uniformity and prevent loss of information -**Otherwise:** When invoking some component, being uncertain which type of errors come in return – it makes proper error -handling much harder. Even worse, using custom types to describe errors might lead to loss of critical error information like the stack trace! +**Otherwise:** When invoking some component, being uncertain which type of errors come in return – it makes proper error handling much harder. Even worse, using custom types to describe errors might lead to loss of critical error information like the stack trace! 🔗 [**Read More: using the built-in error object**](/sections/errorhandling/useonlythebuiltinerror.md) @@ -173,14 +134,9 @@ handling much harder. Even worse, using custom types to describe errors might le ## ![✔] 2.3 Distinguish operational vs programmer errors -**TL;DR:** Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully -understood and can be handled thoughtfully. On the other hand, programmer error (e.g. trying to read undefined variable) -refers to unknown code failures that dictate to gracefully restart the application +**TL;DR:** Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully understood and can be handled thoughtfully. On the other hand, programmer error (e.g. trying to read undefined variable) refers to unknown code failures that dictate to gracefully restart the application -**Otherwise:** You may always restart the application when an error appears, but why let ~5000 online users down because of a -minor, predicted, operational error? the opposite is also not ideal – keeping the application up when an unknown issue -(programmer error) occurred might lead to an unpredicted behavior. Differentiating the two allows acting tactfully and -applying a balanced approach based on the given context +**Otherwise:** You may always restart the application when an error appears, but why let ~5000 online users down because of a minor, predicted, operational error? the opposite is also not ideal – keeping the application up when an unknown issue (programmer error) occurred might lead to an unpredicted behavior. Differentiating the two allows acting tactfully and applying a balanced approach based on the given context 🔗 [**Read More: operational vs programmer error**](/sections/errorhandling/operationalvsprogrammererror.md) @@ -188,8 +144,7 @@ applying a balanced approach based on the given context ## ![✔] 2.4 Handle errors centrally, not within an Express middleware -**TL;DR:** Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object -that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in +**TL;DR:** Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in **Otherwise:** Not handling errors within a single place will lead to code duplication and probably to improperly handled errors @@ -199,12 +154,9 @@ that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when ## ![✔] 2.5 Document API errors using Swagger or GraphQL -**TL;DR:** Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. -For RESTful APIs, this is usually done with documentation frameworks like Swagger. If you're using GraphQL, you can utilize -your schema and comments as well. +**TL;DR:** Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. For RESTful APIs, this is usually done with documentation frameworks like Swagger. If you're using GraphQL, you can utilize your schema and comments as well. -**Otherwise:** An API client might decide to crash and restart only because it received back an error it couldn’t understand. -Note: the caller of your API might be you (very typical in a microservice environment) +**Otherwise:** An API client might decide to crash and restart only because it received back an error it couldn’t understand. Note: the caller of your API might be you (very typical in a microservice environment) 🔗 [**Read More: documenting API errors in Swagger or GraphQL**](/sections/errorhandling/documentingusingswagger.md) @@ -212,12 +164,9 @@ Note: the caller of your API might be you (very typical in a microservice enviro ## ![✔] 2.6 Exit the process gracefully when a stranger comes to town -**TL;DR:** When an unknown error occurs (a developer error, see best practice 2.3) - there is uncertainty about the -application healthiness. A common practice suggests restarting the process carefully using a process management tool like -[Forever](https://www.npmjs.com/package/forever) or [PM2](http://pm2.keymetrics.io/) +**TL;DR:** When an unknown error occurs (a developer error, see best practice 2.3) - there is uncertainty about the application healthiness. A common practice suggests restarting the process carefully using a process management tool like [Forever](https://www.npmjs.com/package/forever) or [PM2](http://pm2.keymetrics.io/) -**Otherwise:** When an unfamiliar exception occurs, some object might be in a faulty state (e.g. an event emitter which is -used globally and not firing events anymore due to some internal failure) and all future requests might fail or behave crazily +**Otherwise:** When an unfamiliar exception occurs, some object might be in a faulty state (e.g. an event emitter which is used globally and not firing events anymore due to some internal failure) and all future requests might fail or behave crazily 🔗 [**Read More: shutting the process**](/sections/errorhandling/shuttingtheprocess.md) @@ -225,12 +174,9 @@ used globally and not firing events anymore due to some internal failure) and al ## ![✔] 2.7 Use a mature logger to increase error visibility -**TL;DR:** A set of mature logging tools like [Winston](https://www.npmjs.com/package/winston), [Bunyan](https://github.com/trentm/node-bunyan), -[Log4js](http://stritti.github.io/log4js/) or [Pino](https://github.com/pinojs/pino), -will speed-up error discovery and understanding. So forget about console.log +**TL;DR:** A set of mature logging tools like [Winston](https://www.npmjs.com/package/winston), [Bunyan](https://github.com/trentm/node-bunyan), [Log4js](http://stritti.github.io/log4js/) or [Pino](https://github.com/pinojs/pino), will speed-up error discovery and understanding. So forget about console.log -**Otherwise:** Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer -might keep you busy at work until late +**Otherwise:** Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer might keep you busy at work until late 🔗 [**Read More: using a mature logger**](/sections/errorhandling/usematurelogger.md) @@ -238,12 +184,9 @@ might keep you busy at work until late ## ![✔] 2.8 Test error flows using your favorite test framework -**TL;DR:** Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies -positive scenarios but also handles and returns the right errors. Testing frameworks like Mocha & Chai can handle this easily -(see code examples within the "Gist popup") +**TL;DR:** Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenarios but also handles and returns the right errors. Testing frameworks like Mocha & Chai can handle this easily (see code examples within the "Gist popup") -**Otherwise:** Without testing, whether automatically or manually, you can’t rely on your code to return the right errors. -Without meaningful errors – there’s no error handling +**Otherwise:** Without testing, whether automatically or manually, you can’t rely on your code to return the right errors. Without meaningful errors – there’s no error handling 🔗 [**Read More: testing error flows**](/sections/errorhandling/testingerrorflows.md) @@ -251,11 +194,9 @@ Without meaningful errors – there’s no error handling ## ![✔] 2.9 Discover errors and downtime using APM products -**TL;DR:** Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can automagically -highlight errors, crashes and slow parts that you were missing +**TL;DR:** Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can automagically highlight errors, crashes and slow parts that you were missing -**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which -are your slowest code parts under real-world scenario and how these affect the UX +**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which are your slowest code parts under real-world scenario and how these affect the UX 🔗 [**Read More: using APM products**](/sections/errorhandling/apmproducts.md) @@ -263,8 +204,7 @@ are your slowest code parts under real-world scenario and how these affect the U ## ![✔] 2.10 Catch unhandled promise rejections -**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to -explicitly handle. Even if your code is subscribed to `process.uncaughtException`! Overcome this by registering to the event `process.unhandledRejection` +**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle. Even if your code is subscribed to `process.uncaughtException`! Overcome this by registering to the event `process.unhandledRejection` **Otherwise:** Your errors will get swallowed and leave no trace. Nothing to worry about @@ -274,12 +214,9 @@ explicitly handle. Even if your code is subscribed to `process.uncaughtException ## ![✔] 2.11 Fail fast, validate arguments using a dedicated library -**TL;DR:** This should be part of your Express best practices – Assert API input to avoid nasty bugs that are much harder to -track later. The validation code is usually tedious unless you are using a very cool helper library like Joi +**TL;DR:** This should be part of your Express best practices – Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a very cool helper library like Joi -**Otherwise:** Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on, -your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a -discount. OMG, what a nasty bug. Can you see it? +**Otherwise:** Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on, your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a discount. OMG, what a nasty bug. Can you see it? 🔗 [**Read More: failing fast**](/sections/errorhandling/failfast.md) @@ -291,11 +228,7 @@ discount. OMG, what a nasty bug. Can you see it? ## ![✔] 3.1 Use ESLint -**TL;DR:** [ESLint](https://eslint.org) is the de-facto standard for checking possible code errors and fixing code style, not -only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors -without classification. Though ESLint can automatically fix code styles, other tools like -[prettier](https://www.npmjs.com/package/prettier) and [beautify](https://www.npmjs.com/package/js-beautify) are more powerful -in formatting the fix and work in conjunction with ESLint +**TL;DR:** [ESLint](https://eslint.org) is the de-facto standard for checking possible code errors and fixing code style, not only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors without classification. Though ESLint can automatically fix code styles, other tools like [prettier](https://www.npmjs.com/package/prettier) and [beautify](https://www.npmjs.com/package/js-beautify) are more powerful in formatting the fix and work in conjunction with ESLint **Otherwise:** Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking the project's code style @@ -305,16 +238,13 @@ in formatting the fix and work in conjunction with ESLint ## ![✔] 3.2 Node.js specific plugins -**TL;DR:** On top of ESLint standard rules that cover vanilla JavaScript, add Node.js specific plugins like -[eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) +**TL;DR:** On top of ESLint standard rules that cover vanilla JavaScript, add Node.js specific plugins like [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) -**Otherwise:** Many faulty Node.js code patterns might escape under the radar. For example, developers might require -(variableAsPath) files with a variable given as path which allows attackers to execute any JS script. Node.js linters can -detect such patterns and complain early +**Otherwise:** Many faulty Node.js code patterns might escape under the radar. For example, developers might require(variableAsPath) files with a variable given as path which allows attackers to execute any JS script. Node.js linters can detect such patterns and complain early

-## ![✔] 3.3 Start a codeblock's Curly Braces on the Same Line +## ![✔] 3.3 Start a Codeblock's Curly Braces on the Same Line **TL;DR:** The opening curly braces of a code block should be on the same line as the opening statement @@ -341,15 +271,11 @@ function someFunction() ## ![✔] 3.4 Separate your statements properly -No matter if you use semicolons or not to separate your statements, knowing the common pitfalls of improper line breaks or -automatic semicolon insertion, will help you to eliminate regular syntax errors. +No matter if you use semicolons or not to separate your statements, knowing the common pitfalls of improper linebreaks or automatic semicolon insertion, will help you to eliminate regular syntax errors. -**TL;DR:** Use ESLint to gain awareness about separation concerns. [Prettier](https://prettier.io/) -or [Standardjs](https://standardjs.com/) can automatically resolve these issues. +**TL;DR:** Use ESLint to gain awareness about separation concerns. [Prettier](https://prettier.io/) or [Standardjs](https://standardjs.com/) can automatically resolve these issues. -**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a -statement if there isn't one, or considers a statement as not ended where it should, which might lead to some undesired -results. You can use assignments and avoid using immediate invoked function expressions to prevent most of unexpected errors. +**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a statement if there isn't one, or considers a statement as not ended where it should, which might lead to some undesired results. You can use assignments and avoid using immediate invoked function expressions to prevent most of unexpected errors. ### Code example @@ -379,8 +305,7 @@ const count = 2 // it tries to run 2(), but 2 is not a function (function doSomething() { // do something amazing }()) -// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous -//function to a variable or avoid IIFEs alltogether +// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous function to a variable or avoid IIFEs alltogether ``` 🔗 [**Read more:** "Semi ESLint rule"](https://eslint.org/docs/rules/semi) @@ -390,23 +315,17 @@ const count = 2 // it tries to run 2(), but 2 is not a function ## ![✔] 3.5 Name your functions -**TL;DR:** Name all functions, including closures and callbacks. Avoid anonymous functions. This is especially useful when -profiling a node app. Naming all functions will allow you to easily understand what you're looking at when checking a memory snapshot +**TL;DR:** Name all functions, including closures and callbacks. Avoid anonymous functions. This is especially useful when profiling a node app. Naming all functions will allow you to easily understand what you're looking at when checking a memory snapshot -**Otherwise:** Debugging production issues using a core dump (memory snapshot) might become challenging as you notice -significant memory consumption from anonymous functions +**Otherwise:** Debugging production issues using a core dump (memory snapshot) might become challenging as you notice significant memory consumption from anonymous functions

## ![✔] 3.6 Use naming conventions for variables, constants, functions and classes -**TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions and **_UpperCamelCase_** (capital first -letter as well) when naming classes. -This will help you to easily distinguish between plain variables/functions, and classes that require instantiation. Use -descriptive names, but try to keep them short +**TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions and **_UpperCamelCase_** (capital first letter as well) when naming classes. This will help you to easily distinguish between plain variables/functions, and classes that require instantiation. Use descriptive names, but try to keep them short -**Otherwise:** Javascript is the only language in the world which allows invoking a constructor ("Class") directly without -instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase +**Otherwise:** Javascript is the only language in the world which allows invoking a constructor ("Class") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase ### 3.6 Code Example @@ -428,11 +347,7 @@ function doSomething() {} ## ![✔] 3.7 Prefer const over let. Ditch the var -**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring `const` will help you to -not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, -in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is -only available in the block scope in which it was defined. `var` is function scoped, not block scoped, and [shouldn't be used -in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have `const` and `let` at your disposal +**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring `const` will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is only available in the block scope in which it was defined. `var` is function scoped, not block scoped, and [shouldn't be used in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have `const` and `let` at your disposal **Otherwise:** Debugging becomes way more cumbersome when following a variable that frequently changes @@ -442,25 +357,19 @@ in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) no ## ![✔] 3.8 Require modules first, not inside functions -**TL;DR:** Require modules at the beginning of each file, before and outside of any functions. This simple best practice will -not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential -problems +**TL;DR:** Require modules at the beginning of each file, before and outside of any functions. This simple best practice will not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential problems -**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other -requests from being handled at a more critical time. Also, if a required module or any of its own dependencies throw an error -and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function +**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its own dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function

## ![✔] 3.9 Require modules by folders, opposed to the files directly -**TL;DR:** When developing a module/library in a folder, place an index.js file that exposes the module's internals so every -consumer will pass through it. This serves as an 'interface' to your module and eases future changes without breaking the -contract +**TL;DR:** When developing a module/library in a folder, place an index.js file that exposes the module's internals so every consumer will pass through it. This serves as an 'interface' to your module and eases future changes without breaking the contract **Otherwise:** Changing the internal structure of files or the signature may break the interface with clients -### 3.8 Code example +### 3.9 Code example ```javascript // Do @@ -476,8 +385,7 @@ module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolve ## ![✔] 3.10 Use the `===` operator -**TL;DR:** Prefer the strict equality operator `===` over the weaker abstract equality operator `==`. `==` will compare two -variables after converting them to a common type. There is no type conversion in `===`, and both variables must be of the same type to be equal +**TL;DR:** Prefer the strict equality operator `===` over the weaker abstract equality operator `==`. `==` will compare two variables after converting them to a common type. There is no type conversion in `===`, and both variables must be of the same type to be equal **Otherwise:** Unequal variables might return true when compared with the `==` operator @@ -504,12 +412,9 @@ All statements above will return false if used with `===` ## ![✔] 3.11 Use Async Await, avoid callbacks -**TL;DR:** Node 8 LTS now has full support for Async-await. This is a new way of dealing with asynchronous code which -supersedes callbacks and promises. Async-await is non-blocking, and it makes asynchronous code look synchronous. The best gift -you can give to your code is using async-await which provides a much more compact and familiar code syntax like try-catch +**TL;DR:** Node 8 LTS now has full support for Async-await. This is a new way of dealing with asynchronous code which supersedes callbacks and promises. Async-await is non-blocking, and it makes asynchronous code look synchronous. The best gift you can give to your code is using async-await which provides a much more compact and familiar code syntax like try-catch -**Otherwise:** Handling async errors in callback style is probably the fastest way to hell - this style forces to check errors -all over, deal with awkward code nesting and makes it difficult to reason about the code flow +**Otherwise:** Handling async errors in callback style is probably the fastest way to hell - this style forces to check errors all over, deal with awkward code nesting and makes it difficult to reason about the code flow 🔗[**Read more:** Guide to async await 1.0](https://github.com/yortus/asyncawait) @@ -517,9 +422,7 @@ all over, deal with awkward code nesting and makes it difficult to reason about ## ![✔] 3.12 Use arrow function expressions (=>) -**TL;DR:** Though it's recommended to use async-await and avoid function parameters when dealing with older APIs that accept -promises or callbacks - arrow functions make the code structure more compact and keep the lexical context of the root function -(i.e. `this`) +**TL;DR:** Though it's recommended to use async-await and avoid function parameters when dealing with older APIs that accept promises or callbacks - arrow functions make the code structure more compact and keep the lexical context of the root function (i.e. `this`) **Otherwise:** Longer code (in ES5 functions) is more prone to bugs and cumbersome to read @@ -533,11 +436,7 @@ promises or callbacks - arrow functions make the code structure more compact and ## ![✔] 4.1 At the very least, write API (component) testing -**TL;DR:** Most projects just don't have any automated testing due to short timetables or often the 'testing project' ran out -of control and was abandoned. For that reason, prioritize and start with API testing which is the easiest way to write and -provides more coverage than unit testing (you may even craft API tests without code using tools like -[Postman](https://www.getpostman.com/). Afterward, should you have more resources and time, continue with advanced test types -like unit testing, DB testing, performance testing, etc +**TL;DR:** Most projects just don't have any automated testing due to short timetables or often the 'testing project' ran out of control and was abandoned. For that reason, prioritize and start with API testing which is the easiest way to write and provides more coverage than unit testing (you may even craft API tests without code using tools like [Postman](https://www.getpostman.com/). Afterward, should you have more resources and time, continue with advanced test types like unit testing, DB testing, performance testing, etc **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage @@ -545,9 +444,7 @@ like unit testing, DB testing, performance testing, etc ## ![✔] 4.2 Include 3 parts in each test name -**TL;DR:** Make the test speak at the requirements level so it's self explanatory also to QA engineers and developers who are -not familiar with the code internals. State in the test name what is being tested (unit under test), under what circumstances -and what is the expected result +**TL;DR:** Make the test speak at the requirements level so it's self explanatory also to QA engineers and developers who are not familiar with the code internals. State in the test name what is being tested (unit under test), under what circumstances and what is the expected result **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning? @@ -557,12 +454,9 @@ and what is the expected result ## ![✔] 4.3 Structure tests by the AAA pattern -**TL;DR:** Structure your tests with 3 well-separated sections: Arrange, Act & Assert (AAA). The first part includes the test -setup, then the execution of the unit under test and finally the assertion phase. Following this structure guarantees that the -reader spends no brain CPU on understanding the test plan +**TL;DR:** Structure your tests with 3 well-separated sections: Arrange, Act & Assert (AAA). The first part includes the test setup, then the execution of the unit under test and finally the assertion phase. Following this structure guarantees that the reader spends no brain CPU on understanding the test plan -**Otherwise:** Not only you spend long daily hours on understanding the main code, now also what should have been the simple -part of the day (testing) stretches your brain +**Otherwise:** Not only you spend long daily hours on understanding the main code, now also what should have been the simple part of the day (testing) stretches your brain 🔗 [**Read More: Structure tests by the AAA pattern**](/sections/testingandquality/aaa.md) @@ -570,8 +464,7 @@ part of the day (testing) stretches your brain ## ![✔] 4.4 Detect code issues with a linter -**TL;DR:** Use a code linter to check basic quality and detect anti-patterns early. Run it before any test and add it as a -pre-commit git-hook to minimize the time needed to review and correct any issue. Also check [Section 3](#3-code-style-practices) on Code Style Practices +**TL;DR:** Use a code linter to check basic quality and detect anti-patterns early. Run it before any test and add it as a pre-commit git-hook to minimize the time needed to review and correct any issue. Also check [Section 3](#3-code-style-practices) on Code Style Practices **Otherwise:** You may let pass some anti-pattern and possible vulnerable code to your production environment. @@ -579,13 +472,9 @@ pre-commit git-hook to minimize the time needed to review and correct any issue. ## ![✔] 4.5 Avoid global test fixtures and seeds, add data per-test -**TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB -rows. Whenever a test needs to pull or assume the existence of some DB data - it must explicitly add that data and avoid -mutating any other records +**TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test needs to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records -**Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious -investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break -the build +**Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break the build 🔗 [**Read More: Avoid global test fixtures**](/sections/testingandquality/avoid-global-test-fixture.md) @@ -593,35 +482,23 @@ the build ## ![✔] 4.6 Constantly inspect for vulnerable dependencies -**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using -community and commercial tools such as 🔗 [npm audit](https://docs.npmjs.com/cli/audit) and 🔗 [snyk.io](https://snyk.io) that -can be invoked from your CI on every build +**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community and commercial tools such as 🔗 [npm audit](https://docs.npmjs.com/cli/audit) and 🔗 [snyk.io](https://snyk.io) that can be invoked from your CI on every build -**Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online -publications about new threats. Quite tedious +**Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious

## ![✔] 4.7 Tag your tests -**TL;DR:** Different tests must run on different scenarios: quick smoke, IO-less, tests should run when a developer saves or -commits a file, full end-to-end tests usually run when a new pull request is submitted, etc. This can be achieved by tagging -tests with keywords like #cold #api #sanity so you can grep with your testing harness and invoke the desired subset. For -example, this is how you would invoke only the sanity test group with [Mocha](https://mochajs.org/): mocha --grep 'sanity' +**TL;DR:** Different tests must run on different scenarios: quick smoke, IO-less, tests should run when a developer saves or commits a file, full end-to-end tests usually run when a new pull request is submitted, etc. This can be achieved by tagging tests with keywords like #cold #api #sanity so you can grep with your testing harness and invoke the desired subset. For example, this is how you would invoke only the sanity test group with [Mocha](https://mochajs.org/): mocha --grep 'sanity' -**Otherwise:** Running all the tests, including tests that perform dozens of DB queries, any time a developer makes a small -change can be extremely slow and keeps developers away from running tests +**Otherwise:** Running all the tests, including tests that perform dozens of DB queries, any time a developer makes a small change can be extremely slow and keeps developers away from running tests

## ![✔] 4.8 Check your test coverage, it helps to identify wrong test patterns -**TL;DR:** Code coverage tools like [Istanbul](https://github.com/istanbuljs/istanbuljs) or -[NYC](https://github.com/istanbuljs/nyc) are great for 3 reasons: it comes for free (no effort is required to benefit this -reports), it helps to identify a decrease in testing coverage, and last but not least it highlights testing mismatches: by -looking at colored code coverage reports you may notice, for example, code areas that are never tested like catch clauses -(meaning that tests only invoke the happy paths and not how the app behaves on errors). Set it to fail builds if the coverage -falls under a certain threshold +**TL;DR:** Code coverage tools like [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) are great for 3 reasons: it comes for free (no effort is required to benefit this reports), it helps to identify a decrease in testing coverage, and last but not least it highlights testing mismatches: by looking at colored code coverage reports you may notice, for example, code areas that are never tested like catch clauses (meaning that tests only invoke the happy paths and not how the app behaves on errors). Set it to fail builds if the coverage falls under a certain threshold **Otherwise:** There won't be any automated metric telling you when a large portion of your code is not covered by testing @@ -629,10 +506,7 @@ falls under a certain threshold ## ![✔] 4.9 Inspect for outdated packages -**TL;DR:** Use your preferred tool (e.g. 'npm outdated' or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) - to detect installed packages which are outdated, inject this check into your CI pipeline and even make a build fail in a -severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local -version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author - kill the build and prevent deploying this version +**TL;DR:** Use your preferred tool (e.g. 'npm outdated' or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) to detect installed packages which are outdated, inject this check into your CI pipeline and even make a build fail in a severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author - kill the build and prevent deploying this version **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky @@ -640,22 +514,15 @@ version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated ## ![✔] 4.10 Use production-like env for e2e testing -**TL;DR:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on -multiple heavy services like DB. Use an environment which is as closed to your real production as possible like a-continue +**TL;DR:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Use an environment which is as closed to your real production as possible like a-continue -**Otherwise:** Without docker-compose teams must maintain a testing DB for each testing environment including developers' -machines, keep all those DBs in sync so test results won't vary across environments +**Otherwise:** Without docker-compose teams must maintain a testing DB for each testing environment including developers' machines, keep all those DBs in sync so test results won't vary across environments

## ![✔] 4.11 Refactor regularly using static analysis tools -**TL;DR:** Using static analysis tools helps by giving objective ways to improve code quality and keeps your code -maintainable. You can add static analysis tools to your CI build to fail when it finds code smells. Its main selling points -over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform -advanced analysis (e.g. code complexity) and follow the history and progress of code issues. Two examples of tools you can use -are [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) and -[Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)). +**TL;DR:** Using static analysis tools helps by giving objective ways to improve code quality and keeps your code maintainable. You can add static analysis tools to your CI build to fail when it finds code smells. Its main selling points over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform advanced analysis (e.g. code complexity) and follow the history and progress of code issues. Two examples of tools you can use are [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)). **Otherwise:** With poor code quality, bugs and performance will always be an issue that no shiny new library or state of the art features can fix @@ -665,15 +532,9 @@ are [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/S ## ![✔] 4.12 Carefully choose your CI platform (Jenkins vs CircleCI vs Travis vs Rest of the world) -**TL;DR:** Your continuous integration platform (CI/CD) will host all the quality tools (e.g test, lint) so it should come -with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the -biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. -Nowadays, it has become much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. -These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a -trade-off between robustness and speed - choose your side carefully +**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. Nowadays, it has become much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully -**Otherwise:** Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, -going with Jenkins might burn precious time on infrastructure setup +**Otherwise:** Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, going with Jenkins might burn precious time on infrastructure setup 🔗 [**Read More: Choosing CI platform**](/sections/testingandquality/citools.md) @@ -685,10 +546,7 @@ going with Jenkins might burn precious time on infrastructure setup ## ![✔] 5.1. Monitoring -**TL;DR:** Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented -importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow -(my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. Click ‘The Gist’ -below for an overview of the solutions +**TL;DR:** Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. Click ‘The Gist’ below for an overview of the solutions **Otherwise:** Failure === disappointed customers. Simple @@ -698,9 +556,7 @@ below for an overview of the solutions ## ![✔] 5.2. Increase transparency using smart logging -**TL;DR:** Logs can be a dumb warehouse of debug statements or the enabler of a beautiful dashboard that tells the story of -your app. Plan your logging platform from day 1: how logs are collected, stored and analyzed to ensure that the desired -information (e.g. error rate, following an entire transaction through services and servers, etc) can really be extracted +**TL;DR:** Logs can be a dumb warehouse of debug statements or the enabler of a beautiful dashboard that tells the story of your app. Plan your logging platform from day 1: how logs are collected, stored and analyzed to ensure that the desired information (e.g. error rate, following an entire transaction through services and servers, etc) can really be extracted **Otherwise:** You end up with a black box that is hard to reason about, then you start re-writing all logging statements to add additional information @@ -710,11 +566,9 @@ information (e.g. error rate, following an entire transaction through services a ## ![✔] 5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy -**TL;DR:** Node is awfully bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use ‘real’ -middleware services like nginx, HAproxy or cloud vendor services instead +**TL;DR:** Node is awfully bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use ‘real’ middleware services like nginx, HAproxy or cloud vendor services instead -**Otherwise:** Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application -core and performance will degrade accordingly +**Otherwise:** Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application core and performance will degrade accordingly 🔗 [**Read More: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy**](/sections/production/delegatetoproxy.md) @@ -722,14 +576,9 @@ core and performance will degrade accordingly ## ![✔] 5.4. Lock dependencies -**TL;DR:** Your code must be identical across all environments, but amazingly npm lets dependencies drift across environments -by default – when you install packages at various environments it tries to fetch packages’ latest patch version. Overcome this -by using npm config files, .npmrc, that tell each environment to save the exact (not the latest) version of each package. -Alternatively, for finer grained control use `npm shrinkwrap`. \*Update: as of NPM5, dependencies are locked by default. The -new package manager in town, Yarn, also got us covered by default +**TL;DR:** Your code must be identical across all environments, but amazingly npm lets dependencies drift across environments by default – when you install packages at various environments it tries to fetch packages’ latest patch version. Overcome this by using npm config files, .npmrc, that tell each environment to save the exact (not the latest) version of each package. Alternatively, for finer grained control use `npm shrinkwrap`. \*Update: as of NPM5, dependencies are locked by default. The new package manager in town, Yarn, also got us covered by default -**Otherwise:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, -different servers in the same production cluster might run different code +**Otherwise:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code 🔗 [**Read More: Lock dependencies**](/sections/production/lockdependencies.md) @@ -737,11 +586,9 @@ different servers in the same production cluster might run different code ## ![✔] 5.5. Guard process uptime using the right tool -**TL;DR:** The process must go on and get restarted upon failures. For simple scenarios, process management tools like PM2 -might be enough but in today's ‘dockerized’ world, cluster management tools should be considered as well +**TL;DR:** The process must go on and get restarted upon failures. For simple scenarios, process management tools like PM2 might be enough but in today's ‘dockerized’ world, cluster management tools should be considered as well -**Otherwise:** Running dozens of instances without a clear strategy and too many tools together (cluster management, Docker, -PM2) might lead to DevOps chaos +**Otherwise:** Running dozens of instances without a clear strategy and too many tools together (cluster management, docker, PM2) might lead to DevOps chaos 🔗 [**Read More: Guard process uptime using the right tool**](/sections/production/guardprocess.md) @@ -749,12 +596,9 @@ PM2) might lead to DevOps chaos ## ![✔] 5.6. Utilize all CPU cores -**TL;DR:** At its basic form, a Node app runs on a single CPU core while all others are left idling. It’s your duty to -replicate the Node process and utilize all CPUs – For small-medium apps you may use Node Cluster or PM2. For a larger app -consider replicating the process using some Docker cluster (e.g. K8S, ECS) or deployment scripts that are based on Linux init system (e.g. systemd) +**TL;DR:** At its basic form, a Node app runs on a single CPU core while all others are left idling. It’s your duty to replicate the Node process and utilize all CPUs – For small-medium apps you may use Node Cluster or PM2. For a larger app consider replicating the process using some Docker cluster (e.g. K8S, ECS) or deployment scripts that are based on Linux init system (e.g. systemd) -**Otherwise:** Your app will likely utilize only 25% of its available resources(!) or even less. Note that a typical server -has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using PaaS services like AWS beanstalk!) +**Otherwise:** Your app will likely utilize only 25% of its available resources(!) or even less. Note that a typical server has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using PaaS services like AWS beanstalk!) 🔗 [**Read More: Utilize all CPU cores**](/sections/production/utilizecpu.md) @@ -762,11 +606,9 @@ has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using ## ![✔] 5.7. Create a ‘maintenance endpoint’ -**TL;DR:** Expose a set of system-related information, like memory usage and REPL, etc in a secured API. Although it’s highly -recommended to rely on standard and battle-tests tools, some valuable information and operations are easier done using code +**TL;DR:** Expose a set of system-related information, like memory usage and REPL, etc in a secured API. Although it’s highly recommended to rely on standard and battle-tests tools, some valuable information and operations are easier done using code -**Otherwise:** You’ll find that you’re performing many “diagnostic deploys” – shipping code to production only to extract some -information for diagnostic purposes +**Otherwise:** You’ll find that you’re performing many “diagnostic deploys” – shipping code to production only to extract some information for diagnostic purposes 🔗 [**Read More: Create a ‘maintenance endpoint’**](/sections/production/createmaintenanceendpoint.md) @@ -774,12 +616,9 @@ information for diagnostic purposes ## ![✔] 5.8. Discover errors and downtime using APM products -**TL;DR:** Application monitoring and performance products (a.k.a APM) proactively gauge codebase and API so they can -auto-magically go beyond traditional monitoring and measure the overall user-experience across services and tiers. For example, - some APM products can highlight a transaction that loads too slow on the end-users side while suggesting the root cause +**TL;DR:** Application monitoring and performance products (a.k.a APM) proactively gauge codebase and API so they can auto-magically go beyond traditional monitoring and measure the overall user-experience across services and tiers. For example, some APM products can highlight a transaction that loads too slow on the end-users side while suggesting the root cause -**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which -is your slowest code parts under real-world scenario and how these affect the UX +**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which is your slowest code parts under real-world scenario and how these affect the UX 🔗 [**Read More: Discover errors and downtime using APM products**](/sections/production/apmproducts.md) @@ -787,8 +626,7 @@ is your slowest code parts under real-world scenario and how these affect the UX ## ![✔] 5.9. Make your code production-ready -**TL;DR:** Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few -development tips that are closely related to production maintenance (click Gist below) +**TL;DR:** Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few development tips that are closely related to production maintenance (click Gist below) **Otherwise:** A world champion IT/DevOps guy won’t save a system that is badly written @@ -798,9 +636,7 @@ development tips that are closely related to production maintenance (click Gist ## ![✔] 5.10. Measure and guard the memory usage -**TL;DR:** Node.js has controversial relationships with memory: the v8 engine has soft limits on memory usage (1.4GB) and -there are known paths to leak memory in Node’s code – thus watching Node’s process memory is a must. In small apps, you may -gauge memory periodically using shell commands but in medium-large apps consider baking your memory watch into a robust monitoring system +**TL;DR:** Node.js has controversial relationships with memory: the v8 engine has soft limits on memory usage (1.4GB) and there are known paths to leak memory in Node’s code – thus watching Node’s process memory is a must. In small apps, you may gauge memory periodically using shell commands but in medium-large apps consider baking your memory watch into a robust monitoring system **Otherwise:** Your process memory might leak a hundred megabytes a day like how it happened at [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak) @@ -810,11 +646,9 @@ gauge memory periodically using shell commands but in medium-large apps consider ## ![✔] 5.11. Get your frontend assets out of Node -**TL;DR:** Serve frontend content using dedicated middleware (nginx, S3, CDN) because Node performance really gets hurt when -dealing with many static files due to its single-threaded model +**TL;DR:** Serve frontend content using dedicated middleware (nginx, S3, CDN) because Node performance really gets hurt when dealing with many static files due to its single-threaded model -**Otherwise:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of -allocating all its resources for the task it was born for – serving dynamic content +**Otherwise:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content 🔗 [**Read More: Get your frontend assets out of Node**](/sections/production/frontendout.md) @@ -822,11 +656,9 @@ allocating all its resources for the task it was born for – serving dynamic co ## ![✔] 5.12. Be stateless, kill your servers almost every day -**TL;DR:** Store any type of data (e.g. user sessions, cache, uploaded files) within external data stores. Consider ‘killing’ -your servers periodically or use ‘serverless’ platform (e.g. AWS Lambda) that explicitly enforces a stateless behavior +**TL;DR:** Store any type of data (e.g. user sessions, cache, uploaded files) within external data stores. Consider ‘killing’ your servers periodically or use ‘serverless’ platform (e.g. AWS Lambda) that explicitly enforces a stateless behavior -**Otherwise:** Failure at a given server will result in application downtime instead of just killing a faulty machine. -Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server +**Otherwise:** Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server 🔗 [**Read More: Be stateless, kill your Servers almost every day**](/sections/production/bestateless.md) @@ -834,12 +666,9 @@ Moreover, scaling-out elasticity will get more challenging due to the reliance o ## ![✔] 5.13. Use tools that automatically detect vulnerabilities -**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a -system at risk. This can be easily tamed using community and commercial tools that constantly check for vulnerabilities and -warn (locally or at GitHub), some can even patch them immediately +**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a system at risk. This can be easily tamed using community and commercial tools that constantly check for vulnerabilities and warn (locally or at GitHub), some can even patch them immediately -**Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require you to constantly follow -online publications about new threats. Quite tedious +**Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require you to constantly follow online publications about new threats. Quite tedious 🔗 [**Read More: Use tools that automatically detect vulnerabilities**](/sections/production/detectvulnerabilities.md) @@ -847,9 +676,7 @@ online publications about new threats. Quite tedious ## ![✔] 5.14. Assign a transaction id to each log statement -**TL;DR:** Assign the same identifier, transaction-id: {some value}, to each log entry within a single request. Then when -inspecting errors in logs, easily conclude what happened before and after. Unfortunately, this is not easy to achieve in Node -due to its async nature, see code examples inside +**TL;DR:** Assign the same identifier, transaction-id: {some value}, to each log entry within a single request. Then when inspecting errors in logs, easily conclude what happened before and after. Unfortunately, this is not easy to achieve in Node due to its async nature, see code examples inside **Otherwise:** Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue @@ -859,11 +686,9 @@ due to its async nature, see code examples inside ## ![✔] 5.15. Set NODE_ENV=production -**TL;DR:** Set the environment variable NODE_ENV to ‘production’ or ‘development’ to flag whether production optimizations -should get activated – many npm packages determine the current environment and optimize their code for production +**TL;DR:** Set the environment variable NODE_ENV to ‘production’ or ‘development’ to flag whether production optimizations should get activated – many npm packages determine the current environment and optimize their code for production -**Otherwise:** Omitting this simple property might greatly degrade performance. For example, when using Express for -server-side rendering omitting `NODE_ENV` makes it slower by a factor of three! +**Otherwise:** Omitting this simple property might greatly degrade performance. For example, when using Express for server-side rendering omitting `NODE_ENV` makes it slower by a factor of three! 🔗 [**Read More: Set NODE_ENV=production**](/sections/production/setnodeenv.md) @@ -871,9 +696,7 @@ server-side rendering omitting `NODE_ENV` makes it slower by a factor of three! ## ![✔] 5.16. Design automated, atomic and zero-downtime deployments -**TL;DR:** Research shows that teams who perform many deployments lower the probability of severe production issues. Fast and -automated deployments that don’t require risky manual steps and service downtime significantly improve the deployment process. -You should probably achieve this using Docker combined with CI tools as they became the industry standard for streamlined deployment +**TL;DR:** Research shows that teams who perform many deployments lower the probability of severe production issues. Fast and automated deployments that don’t require risky manual steps and service downtime significantly improve the deployment process. You should probably achieve this using Docker combined with CI tools as they became the industry standard for streamlined deployment **Otherwise:** Long deployments -> production downtime & human-related error -> team unconfident in making deployment -> fewer deployments and features @@ -883,8 +706,7 @@ You should probably achieve this using Docker combined with CI tools as they bec **TL;DR:** Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements -**Otherwise:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and -your application may become unsupported by various modules and harder to maintain +**Otherwise:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain 🔗 [**Read More: Use an LTS release of Node.js**](/sections/production/LTSrelease.md) @@ -892,9 +714,7 @@ your application may become unsupported by various modules and harder to maintai ## ![✔] 5.18. Don't route logs within the app -**TL;DR:** Log destinations should not be hard-coded by developers within the application code, but instead should be defined -by the execution environment the application runs in. Developers should write logs to `stdout` using a logger utility and then -let the execution environment (container, server, etc.) pipe the `stdout` stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.). +**TL;DR:** Log destinations should not be hard-coded by developers within the application code, but instead should be defined by the execution environment the application runs in. Developers should write logs to `stdout` using a logger utility and then let the execution environment (container, server, etc.) pipe the `stdout` stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.). **Otherwise:** Application handling log routing === hard to scale, loss of logs, poor separation of concerns @@ -912,19 +732,11 @@ let the execution environment (container, server, etc.) pipe the `stdout` stream ## ![✔] 6.1. Embrace linter security rules - - - - + -**TL;DR:** Make use of security-related linter plugins such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) -to catch security vulnerabilities and issues as early as possible, preferably while they're being coded. This can help -catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user -input). Click 'Read more' below to see code examples that will get caught by a security linter +**TL;DR:** Make use of security-related linter plugins such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) to catch security vulnerabilities and issues as early as possible, preferably while they're being coded. This can help catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user input). Click 'Read more' below to see code examples that will get caught by a security linter -**Otherwise:** What could have been a straightforward security weakness during development becomes a major issue in -production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, -or sensitive secrets committed into remote repositories +**Otherwise:** What could have been a straightforward security weakness during development becomes a major issue in production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, or sensitive secrets committed into remote repositories 🔗 [**Read More: Lint rules**](/sections/security/lintrules.md) @@ -932,12 +744,9 @@ or sensitive secrets committed into remote repositories ## ![✔] 6.2. Limit concurrent requests using a middleware - - + -**TL;DR:** DOS attacks are very popular and relatively easy to conduct. Implement rate limiting using an external service such -as cloud load balancers, cloud firewalls, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) -package, or (for smaller and less critical apps) a rate-limiting middleware (e.g. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)) +**TL;DR:** DOS attacks are very popular and relatively easy to conduct. Implement rate limiting using an external service such as cloud load balancers, cloud firewalls, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) package, or (for smaller and less critical apps) a rate-limiting middleware (e.g. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)) **Otherwise:** An application could be subject to an attack resulting in a denial of service where real users receive a degraded or unavailable service. @@ -947,18 +756,11 @@ package, or (for smaller and less critical apps) a rate-limiting middleware (e.g ## ![✔] 6.3 Extract secrets from config files or use packages to encrypt them - - - - + -**TL;DR:** Never store plain-text secrets in configuration files or source code. Instead, make use of secret-management -systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last resort, secrets stored in -source control must be encrypted and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to prevent committing secrets accidentally +**TL;DR:** Never store plain-text secrets in configuration files or source code. Instead, make use of secret-management systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last resort, secrets stored in source control must be encrypted and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to prevent committing secrets accidentally -**Otherwise:** Source control, even for private repositories, can mistakenly be made public, at which point all secrets are -exposed. Access to source control for an external party will inadvertently provide access to related systems (databases, apis, -services, etc). +**Otherwise:** Source control, even for private repositories, can mistakenly be made public, at which point all secrets are exposed. Access to source control for an external party will inadvertently provide access to related systems (databases, apis, services, etc). 🔗 [**Read More: Secret management**](/sections/security/secretmanagement.md) @@ -966,17 +768,11 @@ services, etc). ## ![✔] 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries - - + -**TL;DR:** To prevent SQL/NoSQL injection and other malicious attacks, always make use of an ORM/ODM or a database library -that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected -types. Never just use JavaScript template strings or string concatenation to inject values into queries as this opens your -application to a wide spectrum of vulnerabilities. All the reputable Node.js data access libraries (e.g. [Sequelize](https://github.com/sequelize/sequelize), -[Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) have built-in protection against injection attacks. +**TL;DR:** To prevent SQL/NoSQL injection and other malicious attacks, always make use of an ORM/ODM or a database library that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected types. Never just use JavaScript template strings or string concatenation to inject values into queries as this opens your application to a wide spectrum of vulnerabilities. All the reputable Node.js data access libraries (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) have built-in protection against injection attacks. -**Otherwise:** Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and -not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability. +**Otherwise:** Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability. 🔗 [**Read More: Query injection prevention using ORM/ODM libraries**](/sections/security/ormodmusage.md) @@ -984,8 +780,7 @@ not using a proper sanitization system or ORM will easily allow SQL injection at ## ![✔] 6.5. Collection of generic security best practices -**TL;DR:** This is a collection of security advice that is not related directly to Node.js - the Node implementation is not -much different than any other language. Click read more to skim through. +**TL;DR:** This is a collection of security advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through. 🔗 [**Read More: Common security best practices**](/sections/security/commonsecuritybestpractices.md) @@ -993,11 +788,9 @@ much different than any other language. Click read more to skim through. ## ![✔] 6.6. Adjust the HTTP response headers for enhanced security - - + -**TL;DR:** Your application should be using secure headers to prevent attackers from using common attacks like cross-site -scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like [helmet](https://www.npmjs.com/package/helmet). +**TL;DR:** Your application should be using secure headers to prevent attackers from using common attacks like cross-site scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like [helmet](https://www.npmjs.com/package/helmet). **Otherwise:** Attackers could perform direct attacks on your application's users, leading to huge security vulnerabilities @@ -1007,13 +800,9 @@ scripting (XSS), clickjacking and other malicious attacks. These can be configur ## ![✔] 6.7. Constantly and automatically inspect for vulnerable dependencies - - + -**TL;DR:** With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in -check as new vulnerabilities are found. Use tools like [npm audit](https://docs.npmjs.com/cli/audit) or -[snyk](https://snyk.io/) to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you -catch a vulnerable dependency before it makes it to production. +**TL;DR:** With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in check as new vulnerabilities are found. Use tools like [npm audit](https://docs.npmjs.com/cli/audit) or [snyk](https://snyk.io/) to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you catch a vulnerable dependency before it makes it to production. **Otherwise:** An attacker could detect your web framework and attack all its known vulnerabilities. @@ -1023,14 +812,11 @@ catch a vulnerable dependency before it makes it to production. ## ![✔] 6.8. Avoid using the Node.js crypto library for handling passwords, use Bcrypt - - + -**TL;DR:** Passwords or secrets (API keys) should be stored using a secure hash + salt function like `bcrypt`, that should be -a preferred choice over its JavaScript implementation due to performance and security reasons. +**TL;DR:** Passwords or secrets (API keys) should be stored using a secure hash + salt function like `bcrypt`, that should be a preferred choice over its JavaScript implementation due to performance and security reasons. -**Otherwise:** Passwords or secrets that are persisted without using a secure function are vulnerable to brute forcing and -dictionary attacks that will lead to their disclosure eventually. +**Otherwise:** Passwords or secrets that are persisted without using a secure function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually. 🔗 [**Read More: Use Bcrypt**](/sections/security/bcryptpasswords.md) @@ -1038,12 +824,9 @@ dictionary attacks that will lead to their disclosure eventually. ## ![✔] 6.9. Escape HTML, JS and CSS output - - + -**TL;DR:** Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is -commonly referred as a cross-site-scripting (XSS) attack. Mitigate this by using dedicated libraries that explicitly mark the -data as pure content that should never get executed (i.e. encoding, escaping) +**TL;DR:** Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is commonly referred as a cross-site-scripting (XSS) attack. Mitigate this by using dedicated libraries that explicitly mark the data as pure content that should never get executed (i.e. encoding, escaping) **Otherwise:** An attacker might store malicious JavaScript code in your DB which will then be sent as-is to the poor clients @@ -1053,17 +836,11 @@ data as pure content that should never get executed (i.e. encoding, escaping) ## ![✔] 6.10. Validate incoming JSON schemas - - - - + -**TL;DR:** Validate the incoming requests' body payload and ensure it meets expectations, fail fast if it doesn't. To avoid -tedious validation coding within each route you may use lightweight JSON-based validation schemas such as -[jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi) +**TL;DR:** Validate the incoming requests' body payload and ensure it meets expectations, fail fast if it doesn't. To avoid tedious validation coding within each route you may use lightweight JSON-based validation schemas such as [jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi) -**Otherwise:** Your generosity and permissive approach greatly increases the attack surface and encourages the attacker to try -out many inputs until they find some combination to crash the application +**Otherwise:** Your generosity and permissive approach greatly increases the attack surface and encourages the attacker to try out many inputs until they find some combination to crash the application 🔗 [**Read More: Validate incoming JSON schemas**](/sections/security/validation.md) @@ -1071,13 +848,9 @@ out many inputs until they find some combination to crash the application ## ![✔] 6.11. Support blacklisting JWTs - - + -**TL;DR:** When using JSON Web Tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default -there's no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there's no way to -stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blacklist of untrusted -tokens that are validated on each request. +**TL;DR:** When using JSON Web Tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default there's no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there's no way to stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blacklist of untrusted tokens that are validated on each request. **Otherwise:** Expired, or misplaced tokens could be used maliciously by a third party to access an application and impersonate the owner of the token. @@ -1087,14 +860,12 @@ tokens that are validated on each request. ## ![✔] 6.12. Prevent brute-force attacks against authorization - - + **TL;DR:** A simple and powerful technique is to limit authorization attempts using two metrics: 1. The first is number of consecutive failed attempts by the same user unique ID/name and IP address. -2. The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address -if it makes 100 failed attempts in one day. +2. The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day. **Otherwise:** An attacker can issue unlimited automated password attempts to gain access to privileged accounts on an application @@ -1104,15 +875,11 @@ if it makes 100 failed attempts in one day. ## ![✔] 6.13. Run Node.js as non-root user - - + -**TL;DR:** There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the -default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image -(examples given below) or run the process on this user's behalf by invoking the container with the flag "-u username" +**TL;DR:** There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image (examples given below) or run the process on this user's behalf by invoking the container with the flag "-u username" -**Otherwise:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change -iptable and re-route traffic to his server) +**Otherwise:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to his server) 🔗 [**Read More: Run Node.js as non-root user**](/sections/security/non-root-user.md) @@ -1120,18 +887,11 @@ iptable and re-route traffic to his server) ## ![✔] 6.14. Limit payload size using a reverse-proxy or a middleware - - - - + -**TL;DR:** The bigger the body payload is, the harder your single thread works in processing it. This is an opportunity for -attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the -body size of incoming requests on the edge (e.g. firewall, ELB) or by configuring -[Express.js body parser](https://github.com/expressjs/body-parser) to accept only small-size payloads +**TL;DR:** The bigger the body payload is, the harder your single thread works in processing it. This is an opportunity for attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the body size of incoming requests on the edge (e.g. firewall, ELB) or by configuring [express body parser](https://github.com/expressjs/body-parser) to accept only small-size payloads -**Otherwise:** Your application will have to deal with large requests, unable to process the other important work it has to -accomplish, leading to performance implications and vulnerability towards DOS attacks +**Otherwise:** Your application will have to deal with large requests, unable to process the other important work it has to accomplish, leading to performance implications and vulnerability towards DOS attacks 🔗 [**Read More: Limit payload size**](/sections/security/requestpayloadsizelimit.md) @@ -1139,19 +899,11 @@ accomplish, leading to performance implications and vulnerability towards DOS at ## ![✔] 6.15. Avoid JavaScript eval statements - - - - - - + -**TL;DR:** `eval` is evil as it allows executing custom JavaScript code during run time. This is not just a performance -concern but also an important security concern due to malicious JavaScript code that may be sourced from user input. Another -language feature that should be avoided is `new Function` constructor. `setTimeout` and `setInterval` should never be passed dynamic JavaScript code either. +**TL;DR:** `eval` is evil as it allows executing custom JavaScript code during run time. This is not just a performance concern but also an important security concern due to malicious JavaScript code that may be sourced from user input. Another language feature that should be avoided is `new Function` constructor. `setTimeout` and `setInterval` should never be passed dynamic JavaScript code either. -**Otherwise:** Malicious JavaScript code finds a way into text passed into `eval` or other real-time evaluating JavaScript -language functions, and will gain complete access to JavaScript permissions on the page. This vulnerability is often manifested as an XSS attack. +**Otherwise:** Malicious JavaScript code finds a way into text passed into `eval` or other real-time evaluating JavaScript language functions, and will gain complete access to JavaScript permissions on the page. This vulnerability is often manifested as an XSS attack. 🔗 [**Read More: Avoid JavaScript eval statements**](/sections/security/avoideval.md) @@ -1159,18 +911,11 @@ language functions, and will gain complete access to JavaScript permissions on t ## ![✔] 6.16. Prevent evil RegEx from overloading your single thread execution - - + -**TL;DR:** Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js -platform in particular. A user input for text to match might require an outstanding amount of CPU cycles to process. RegEx -processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for -6 seconds and set the CPU on 🔥. For that reason, prefer third-party validation packages like -[validator.js](https://github.com/chriso/validator.js) instead of writing your own Regex patterns, or make use of [safe-regex](https://github.com/substack/safe-regex) -to detect vulnerable regex patterns +**TL;DR:** Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js platform in particular. A user input for text to match might require an outstanding amount of CPU cycles to process. RegEx processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for 6 seconds and set the CPU on 🔥. For that reason, prefer third-party validation packages like [validator.js](https://github.com/chriso/validator.js) instead of writing your own Regex patterns, or make use of [safe-regex](https://github.com/substack/safe-regex) to detect vulnerable regex patterns -**Otherwise:** Poorly written regexes could be susceptible to Regular Expression DoS attacks that will block the event loop -completely. For example, the popular `moment` package was found vulnerable with malicious RegEx usage in November of 2017 +**Otherwise:** Poorly written regexes could be susceptible to Regular Expression DoS attacks that will block the event loop completely. For example, the popular `moment` package was found vulnerable with malicious RegEx usage in November of 2017 🔗 [**Read More: Prevent malicious RegEx**](/sections/security/regex.md) @@ -1178,20 +923,11 @@ completely. For example, the popular `moment` package was found vulnerable with ## ![✔] 6.17. Avoid module loading using a variable - - - - - - + -**TL;DR:** Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could -have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other -sensitive resource access with dynamic variables originating from user input. -[Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter can catch such patterns and warn early enough +**TL;DR:** Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resource access with dynamic variables originating from user input. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter can catch such patterns and warn early enough -**Otherwise:** Malicious user input could find its way to a parameter that is used to require tampered files, for example, a -previously uploaded file on the filesystem, or access already existing system files. +**Otherwise:** Malicious user input could find its way to a parameter that is used to require tampered files, for example, a previously uploaded file on the filesystem, or access already existing system files. 🔗 [**Read More: Safe module loading**](/sections/security/safemoduleloading.md) @@ -1199,19 +935,11 @@ previously uploaded file on the filesystem, or access already existing system fi ## ![✔] 6.18. Run unsafe code in a sandbox - - - - - - + -**TL;DR:** When tasked to run external code that is given at run-time (e.g. plugin), use any sort of 'sandbox' execution -environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process -(e.g. `cluster.fork()`), serverless environment or dedicated npm packages that act as a sandbox +**TL;DR:** When tasked to run external code that is given at run-time (e.g. plugin), use any sort of 'sandbox' execution environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process (e.g. `cluster.fork()`), serverless environment or dedicated npm packages that act as a sandbox -**Otherwise:** A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access -to sensitive process environment variables +**Otherwise:** A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access to sensitive process environment variables 🔗 [**Read More: Run unsafe code in a sandbox**](/sections/security/sandbox.md) @@ -1219,19 +947,11 @@ to sensitive process environment variables ## ![✔] 6.19. Take extra care when working with child processes - - - - - - + -**TL;DR:** Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if -you still have to. Prefer using `child_process.execFile` which by definition will only execute a single command with a set of -attributes and will not allow shell parameter expansion. +**TL;DR:** Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if you still have to. Prefer using `child_process.execFile` which by definition will only execute a single command with a set of attributes and will not allow shell parameter expansion. -**Otherwise:** Naive use of child processes could result in remote command execution or shell injection attacks due to -malicious user input passed to an unsanitized system command. +**Otherwise:** Naive use of child processes could result in remote command execution or shell injection attacks due to malicious user input passed to an unsanitized system command. 🔗 [**Read More: Be cautious when working with child processes**](/sections/security/childprocesses.md) @@ -1239,15 +959,11 @@ malicious user input passed to an unsanitized system command. ## ![✔] 6.20. Hide error details from clients - - + -**TL;DR:** An integrated express error handler hides the error details by default. However, great are the chances that you -implement your own error handling logic with custom Error objects (considered by many as a best practice). If you do so, -ensure not to return the entire Error object to the client, which might contain some sensitive application details +**TL;DR:** An integrated express error handler hides the error details by default. However, great are the chances that you implement your own error handling logic with custom Error objects (considered by many as a best practice). If you do so, ensure not to return the entire Error object to the client, which might contain some sensitive application details -**Otherwise:** Sensitive application details such as server file paths, third party modules in use, and other internal -workflows of the application which could be exploited by an attacker, could be leaked from information found in a stack trace +**Otherwise:** Sensitive application details such as server file paths, third party modules in use, and other internal workflows of the application which could be exploited by an attacker, could be leaked from information found in a stack trace 🔗 [**Read More: Hide error details from client**](/sections/security/hideerrors.md) @@ -1255,13 +971,9 @@ workflows of the application which could be exploited by an attacker, could be l ## ![✔] 6.21. Configure 2FA for npm or Yarn - - + -**TL;DR:** Any step in the development chain should be protected with MFA (multi-factor authentication), npm/Yarn are a sweet -opportunity for attackers who can get their hands on some developer's password. Using developer credentials, attackers can -inject malicious code into libraries that are widely installed across projects and services. Maybe even across the web if -published in public. Enabling 2-factor-authentication in npm leaves almost zero chances for attackers to alter your package code. +**TL;DR:** Any step in the development chain should be protected with MFA (multi-factor authentication), npm/Yarn are a sweet opportunity for attackers who can get their hands on some developer's password. Using developer credentials, attackers can inject malicious code into libraries that are widely installed across projects and services. Maybe even across the web if published in public. Enabling 2-factor-authentication in npm leaves almost zero chances for attackers to alter your package code. **Otherwise:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) @@ -1269,16 +981,11 @@ published in public. Enabling 2-factor-authentication in npm leaves almost zero ## ![✔] 6.22. Modify session middleware settings - - + -**TL;DR:** Each web framework and technology has its known weaknesses - telling an attacker which web framework we use is a -great help for them. Using the default settings for session middlewares can expose your app to module- and framework-specific -hijacking attacks in a similar way to the `X-Powered-By` header. Try hiding anything that identifies and reveals your tech -stack (E.g. Node.js, express) +**TL;DR:** Each web framework and technology has its known weaknesses - telling an attacker which web framework we use is a great help for them. Using the default settings for session middlewares can expose your app to module- and framework-specific hijacking attacks in a similar way to the `X-Powered-By` header. Try hiding anything that identifies and reveals your tech stack (E.g. Node.js, express) -**Otherwise:** Cookies could be sent over insecure connections, and an attacker might use session identification to identify -the underlying framework of the web application, as well as module-specific vulnerabilities +**Otherwise:** Cookies could be sent over insecure connections, and an attacker might use session identification to identify the underlying framework of the web application, as well as module-specific vulnerabilities 🔗 [**Read More: Cookie and session security**](/sections/security/sessions.md) @@ -1286,32 +993,21 @@ the underlying framework of the web application, as well as module-specific vuln ## ![✔] 6.23. Avoid DOS attacks by explicitly setting when a process should crash - - + -**TL;DR:** The Node process will crash when errors are not handled. Many best practices even recommend to exit even though an -error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a -catch clause. This opens a very sweet attack spot for attackers who recognize what input makes the process crash and -repeatedly send the same request. There's no instant remedy for this but a few techniques can mitigate the pain: Alert with -critical severity anytime a process crashes due to an unhandled error, validate the input and avoid crashing the process due -to invalid user input, wrap all routes with a catch and consider not to crash when an error originated within a request (as -opposed to what happens globally) +**TL;DR:** The Node process will crash when errors are not handled. Many best practices even recommend to exit even though an error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a catch clause. This opens a very sweet attack spot for attackers who recognize what input makes the process crash and repeatedly send the same request. There's no instant remedy for this but a few techniques can mitigate the pain: Alert with critical severity anytime a process crashes due to an unhandled error, validate the input and avoid crashing the process due to invalid user input, wrap all routes with a catch and consider not to crash when an error originated within a request (as opposed to what happens globally) -**Otherwise:** This is just an educated guess: given many Node.js applications, if we try passing an empty JSON body to all -POST requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take down the applications with ease +**Otherwise:** This is just an educated guess: given many Node.js applications, if we try passing an empty JSON body to all POST requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take down the applications with ease

## ![✔] 6.24. Prevent unsafe redirects - - + -**TL;DR:** Redirects that do not validate user input can enable attackers to launch phishing scams, steal user credentials, -and perform other malicious actions. +**TL;DR:** Redirects that do not validate user input can enable attackers to launch phishing scams, steal user credentials, and perform other malicious actions. -**Otherwise:** If an attacker discovers that you are not validating external, user-supplied input, they may exploit this -vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it. +**Otherwise:** If an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it. 🔗 [**Read More: Prevent unsafe redirects**](/sections/security/saferedirects.md) @@ -1319,15 +1015,11 @@ vulnerability by posting specially-crafted links on forums, social media, and ot ## ![✔] 6.25. Avoid publishing secrets to the npm registry - - + -**TL;DR:** Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An -`.npmignore` file can be used to blacklist specific files or folders, or the `files` array in `package.json` can act as a -whitelist. +**TL;DR:** Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An `.npmignore` file can be used to blacklist specific files or folders, or the `files` array in `package.json` can act as a whitelist. -**Otherwise:** Your project's API keys, passwords or other secrets are open to be abused by anyone who comes across them, -which may result in financial loss, impersonation, and other risks. +**Otherwise:** Your project's API keys, passwords or other secrets are open to be abused by anyone who comes across them, which may result in financial loss, impersonation, and other risks. 🔗 [**Read More: Avoid publishing secrets**](/sections/security/avoid_publishing_secrets.md)


@@ -1340,13 +1032,10 @@ which may result in financial loss, impersonation, and other risks. ## ![✔] 7.1. Prefer native JS methods over user-land utils like Lodash - **TL;DR:** It's often more penalizing to use utility libraries like `lodash` and `underscore` over native methods as it leads - to unneeded dependencies and slower performance. - Bear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in - such a way that it's now about 50% more performant than utility libraries. + **TL;DR:** It's often more penalising to use utility libraries like `lodash` and `underscore` over native methods as it leads to unneeded dependencies and slower performance. + Bear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in such a way that it's now about 50% more performant than utility libraries. -**Otherwise:** You'll have to maintain less performant projects where you could have simply used what was **already** -available or dealt with a few more lines in exchange of a few more files. +**Otherwise:** You'll have to maintain less performant projects where you could have simply used what was **already** available or dealt with a few more lines in exchange of a few more files. 🔗 [**Read More: Native over user land utils**](/sections/performance/nativeoverutil.md) @@ -1354,9 +1043,7 @@ available or dealt with a few more lines in exchange of a few more files. # Milestones -To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with -the help of the community. You can follow our [milestones](https://github.com/i0natan/nodebestpractices/milestones) and join -the working groups if you want to contribute to this project +To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/i0natan/nodebestpractices/milestones) and join the working groups if you want to contribute to this project
@@ -1382,8 +1069,7 @@ All translations are contributed by the community. We will be happy to get any h ## Steering Committee -Meet the steering committee members - the people who work together to provide guidance and future direction to the project. In -addition, each member of the committee leads a project tracked under our [Github projects](https://github.com/i0natan/nodebestpractices/projects). +Meet the steering committee members - the people who work together to provide guidance and future direction to the project. In addition, each member of the committee leads a project tracked under our [Github projects](https://github.com/i0natan/nodebestpractices/projects). @@ -1391,9 +1077,7 @@ addition, each member of the committee leads a project tracked under our [Github -Independent Node.js consultant who works with customers in USA, Europe, and Israel on building large scale scalable Node -applications. Many of the best practices above were first published at [goldbergyoni.com](https://goldbergyoni.com). Reach -Yoni at @goldbergyoni or me@goldbergyoni.com +Independent Node.js consultant who works with customers in USA, Europe, and Israel on building large scale scalable Node applications. Many of the best practices above were first published at [goldbergyoni.com](https://goldbergyoni.com). Reach Yoni at @goldbergyoni or me@goldbergyoni.com
@@ -1412,8 +1096,7 @@ Yoni at @goldbergyoni or me@goldbergyoni.com -Full Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and -architecting and building Node.js applications to perform at global scale. +Full Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and architecting and building Node.js applications to perform at global scale.
@@ -1424,9 +1107,7 @@ architecting and building Node.js applications to perform at global scale. -Deep specialist in JavaScript and its ecosystem — React, Node.js, MongoDB, pretty much anything that involves using -JavaScript/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. -Individual Member of the Node.js Foundation, collaborating on the Community Committee's Website Redesign Initiative. +Deep specialist in JavaScript and its ecosystem — React, Node.js, MongoDB, pretty much anything that involves using JavaScript/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. Individual Member of the Node.js Foundation, collaborating on the Community Committee's Website Redesign Initiative.
@@ -1434,20 +1115,17 @@ Individual Member of the Node.js Foundation, collaborating on the Community Comm Thank you to all our collaborators! 🙏 -Our collaborators are members who are contributing to the repository on a regular basis, through suggesting new best practices - triaging issues, reviewing pull requests and more. If you are interested in helping us guide thousands of people to craft -better Node.js applications, please read our [contributor guidelines](/.operations/CONTRIBUTING.md) 🎉 +Our collaborators are members who are contributing to the repository on a regular basis, through suggesting new best practices, triaging issues, reviewing pull requests and more. If you are interested in helping us guide thousands of people to craft better Node.js applications, please read our [contributor guidelines](/.operations/CONTRIBUTING.md) 🎉 - -[Ido Richter (Founder)](https://github.com/idori) - - -[Keith Holliday](https://github.com/TheHollidayInn) +| | | +| :--: | :--: | +| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | ### Past collaborators - -[Refael Ackermann](https://github.com/refack) +| | +| :--: | +| [Refael Ackermann](https://github.com/refack) |