[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-323":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":23,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":44,"readmeContent":45,"aiSummary":46,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":47,"discoverSource":48},323,"nodebestpractices","goldbergyoni\u002Fnodebestpractices","goldbergyoni","✅ The Node.js best practices list (July 2026)","https:\u002F\u002Ftwitter.com\u002Fnodepractices\u002F",null,"Dockerfile",105330,10720,1927,52,0,2,31,104,19,99.5,"Creative Commons Attribution Share Alike 4.0 International",false,"master",[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"best-practices","es6","eslint","express","expressjs","javascript","jest","microservices","mocha","node-js","nodejs","nodejs-development","npm","rest","style-guide","styleguide","testing","types","2026-06-17 04:00:02","[✔]: assets\u002Fimages\u002Fcheckbox-small-blue.png\n\n# Node.js Best Practices\n\n\u003Ch1 align=\"center\">\n  \u003Cimg src=\"assets\u002Fimages\u002Fbanner-2.jpg\" alt=\"Node.js Best Practices\"\u002F>\n\u003C\u002Fh1>\n\n\u003Cbr\u002F>\n\n\u003Cdiv align=\"center\">\n  \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F⚙%20Item%20count%20-%20102%20Best%20Practices-blue.svg\" alt=\"102 items\"\u002F> \u003Cimg id=\"last-update-badge\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F%F0%9F%93%85%20Last%20update%20-%20January%2024%2C%202023-green.svg\" alt=\"Last update: January 3rd, 2024\" \u002F> \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F %E2%9C%94%20Updated%20For%20Version%20-%20Node%2022.0.0-brightgreen.svg\" alt=\"Updated for Node 22.0.0\"\u002F>\n\u003C\u002Fdiv>\n\n\u003Cbr\u002F>\n\n[\u003Cimg src=\"assets\u002Fimages\u002Ftwitter.svg\" width=\"16\" height=\"16\" alt=\"\" \u002F>](https:\u002F\u002Ftwitter.com\u002Fnodepractices\u002F) **Follow us on Twitter!** [**@nodepractices**](https:\u002F\u002Ftwitter.com\u002Fnodepractices\u002F)\n\n\u003Cbr\u002F>\n\nRead in a different language: [![CN](.\u002Fassets\u002Fflags\u002FCN.png)**CN**](.\u002FREADME.chinese.md), [![FR](.\u002Fassets\u002Fflags\u002FFR.png)**FR**](.\u002FREADME.french.md), [![BR](.\u002Fassets\u002Fflags\u002FBR.png)**BR**](.\u002FREADME.brazilian-portuguese.md), [![RU](.\u002Fassets\u002Fflags\u002FRU.png)**RU**](.\u002FREADME.russian.md), [![PL](.\u002Fassets\u002Fflags\u002FPL.png)**PL**](.\u002FREADME.polish.md), [![JA](.\u002Fassets\u002Fflags\u002FJA.png)**JA**](.\u002FREADME.japanese.md), [![EU](.\u002Fassets\u002Fflags\u002FEU.png)**EU**](.\u002FREADME.basque.md) [(![ES](.\u002Fassets\u002Fflags\u002FES.png)**ES**, ![HE](.\u002Fassets\u002Fflags\u002FHE.png)**HE**, ![KR](.\u002Fassets\u002Fflags\u002FKR.png)**KR** and ![TR](.\u002Fassets\u002Fflags\u002FTR.png)**TR** in progress! )](#translations)\n\n\u003Cbr\u002F>\n\n# 🎊 2024 edition is here!\n\n- **🛰 Modernized to 2024**: Tons of text edits, new recommended libraries, and some new best practices\n\n- **✨ Easily focus on new content**: Already visited before? Search for `#new` or `#updated` tags for new content only\n\n- **🔖 Curious to see examples? We have a starter**: Visit [Practica.js](https:\u002F\u002Fgithub.com\u002Fpracticajs\u002Fpractica), our application example and boilerplate (beta) to see some practices in action\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# Welcome! 3 Things You Ought To Know First\n\n**1. You are 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\n\n**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](.\u002F.operations\u002Fwriting-guidelines.md)\n\n**3. 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\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# By Yoni Goldberg\n\n### Learn with me: As a consultant, I engage with worldwide teams on various activities like workshops and code reviews. 🎉AND... Hold on, I've just launched my [beyond-the-basics testing course, which is on a 🎁 limited-time sale](https:\u002F\u002Ftestjavascript.com\u002F) until August 7th\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## Table of Contents\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#1-project-architecture-practices\">1. Project Architecture Practices (6)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[1.1 Structure your solution by components `#strategic` `#updated`](#-11-structure-your-solution-by-business-components)\u003C\u002Fbr>\n&emsp;&emsp;[1.2 Layer your components, keep the web layer within its boundaries `#strategic` `#updated`](#-12-layer-your-components-with-3-tiers-keep-the-web-layer-within-its-boundaries)\u003C\u002Fbr>\n&emsp;&emsp;[1.3 Wrap common utilities as packages, consider publishing](#-13-wrap-common-utilities-as-packages-consider-publishing)\u003C\u002Fbr>\n&emsp;&emsp;[1.4 Use environment aware, secure and hierarchical config `#updated`](#-14-use-environment-aware-secure-and-hierarchical-config)\u003C\u002Fbr>\n&emsp;&emsp;[1.5 Consider all the consequences when choosing the main framework `#new`](#-15-consider-all-the-consequences-when-choosing-the-main-framework)\u003C\u002Fbr>\n&emsp;&emsp;[1.6 Use TypeScript sparingly and thoughtfully `#new`](#-16-use-typescript-sparingly-and-thoughtfully)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#2-error-handling-practices\">2. Error Handling Practices (12)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[2.1 Use Async-Await or promises for async error handling](#-21-use-async-await-or-promises-for-async-error-handling)\u003C\u002Fbr>\n&emsp;&emsp;[2.2 Extend the built-in Error object `#strategic` `#updated`](#-22-extend-the-built-in-error-object)\u003C\u002Fbr>\n&emsp;&emsp;[2.3 Distinguish operational vs programmer errors `#strategic` `#updated`](#-23-distinguish-catastrophic-errors-from-operational-errors)\u003C\u002Fbr>\n&emsp;&emsp;[2.4 Handle errors centrally, not within a middleware `#strategic`](#-24-handle-errors-centrally-not-within-a-middleware)\u003C\u002Fbr>\n&emsp;&emsp;[2.5 Document API errors using OpenAPI or GraphQL](#-25-document-api-errors-using-openapi-or-graphql)\u003C\u002Fbr>\n&emsp;&emsp;[2.6 Exit the process gracefully when a stranger comes to town `#strategic`](#-26-exit-the-process-gracefully-when-a-stranger-comes-to-town)\u003C\u002Fbr>\n&emsp;&emsp;[2.7 Use a mature logger to increase errors visibility `#updated`](#-27-use-a-mature-logger-to-increase-errors-visibility)\u003C\u002Fbr>\n&emsp;&emsp;[2.8 Test error flows using your favorite test framework `#updated`](#-28-test-error-flows-using-your-favorite-test-framework)\u003C\u002Fbr>\n&emsp;&emsp;[2.9 Discover errors and downtime using APM products](#-29-discover-errors-and-downtime-using-apm-products)\u003C\u002Fbr>\n&emsp;&emsp;[2.10 Catch unhandled promise rejections `#updated`](#-210-catch-unhandled-promise-rejections)\u003C\u002Fbr>\n&emsp;&emsp;[2.11 Fail fast, validate arguments using a dedicated library](#-211-fail-fast-validate-arguments-using-a-dedicated-library)\u003C\u002Fbr>\n&emsp;&emsp;[2.12 Always await promises before returning to avoid a partial stacktrace `#new`](#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace)\u003C\u002Fbr>\n&emsp;&emsp;[2.13 Subscribe to event emitters 'error' event `#new`](#-213-subscribe-to-event-emitters-and-streams-error-event)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#3-code-patterns-and-style-practices\">3. Code Style Practices (12)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[3.1 Use ESLint `#strategic`](#-31-use-eslint)\u003C\u002Fbr>\n&emsp;&emsp;[3.2 Use Node.js eslint extension plugins `#updated`](#-32-use-nodejs-eslint-extension-plugins)\u003C\u002Fbr>\n&emsp;&emsp;[3.3 Start a Codeblock's Curly Braces on the Same Line](#-33-start-a-codeblocks-curly-braces-on-the-same-line)\u003C\u002Fbr>\n&emsp;&emsp;[3.4 Separate your statements properly](#-34-separate-your-statements-properly)\u003C\u002Fbr>\n&emsp;&emsp;[3.5 Name your functions](#-35-name-your-functions)\u003C\u002Fbr>\n&emsp;&emsp;[3.6 Use naming conventions for variables, constants, functions and classes](#-36-use-naming-conventions-for-variables-constants-functions-and-classes)\u003C\u002Fbr>\n&emsp;&emsp;[3.7 Prefer const over let. Ditch the var](#-37-prefer-const-over-let-ditch-the-var)\u003C\u002Fbr>\n&emsp;&emsp;[3.8 Require modules first, not inside functions](#-38-require-modules-first-not-inside-functions)\u003C\u002Fbr>\n&emsp;&emsp;[3.9 Set an explicit entry point to a module\u002Ffolder `#updated`](#-39-set-an-explicit-entry-point-to-a-modulefolder)\u003C\u002Fbr>\n&emsp;&emsp;[3.10 Use the === operator](#-310-use-the--operator)\u003C\u002Fbr>\n&emsp;&emsp;[3.11 Use Async Await, avoid callbacks `#strategic`](#-311-use-async-await-avoid-callbacks)\u003C\u002Fbr>\n&emsp;&emsp;[3.12 Use arrow function expressions (=>)](#-312-use-arrow-function-expressions-)\u003C\u002Fbr>\n&emsp;&emsp;[3.13 Avoid effects outside of functions `#new`](#-313-avoid-effects-outside-of-functions)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#4-testing-and-overall-quality-practices\">4. Testing And Overall Quality Practices (13)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[4.1 At the very least, write API (component) testing `#strategic`](#-41-at-the-very-least-write-api-component-testing)\u003C\u002Fbr>\n&emsp;&emsp;[4.2 Include 3 parts in each test name `#new`](#-42-include-3-parts-in-each-test-name)\u003C\u002Fbr>\n&emsp;&emsp;[4.3 Structure tests by the AAA pattern `#strategic`](#-43-structure-tests-by-the-aaa-pattern)\u003C\u002Fbr>\n&emsp;&emsp;[4.4 Ensure Node version is unified `#new`](#-44-ensure-node-version-is-unified)\u003C\u002Fbr>\n&emsp;&emsp;[4.5 Avoid global test fixtures and seeds, add data per-test `#strategic`](#-45-avoid-global-test-fixtures-and-seeds-add-data-per-test)\u003C\u002Fbr>\n&emsp;&emsp;[4.6 Tag your tests `#advanced`](#-46-tag-your-tests)\u003C\u002Fbr>\n&emsp;&emsp;[4.7 Check your test coverage, it helps to identify wrong test patterns](#-47-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns)\u003C\u002Fbr>\n&emsp;&emsp;[4.8 Use production-like environment for e2e testing](#-48-use-production-like-environment-for-e2e-testing)\u003C\u002Fbr>\n&emsp;&emsp;[4.9 Refactor regularly using static analysis tools](#-49-refactor-regularly-using-static-analysis-tools)\u003C\u002Fbr>\n&emsp;&emsp;[4.10 Mock responses of external HTTP services #advanced `#new` `#advanced`](#-410-mock-responses-of-external-http-services)\u003C\u002Fbr>\n&emsp;&emsp;[4.11 Test your middlewares in isolation](#-411-test-your-middlewares-in-isolation)\u003C\u002Fbr>\n&emsp;&emsp;[4.12 Specify a port in production, randomize in testing `#new`](#-412-specify-a-port-in-production-randomize-in-testing)\u003C\u002Fbr>\n&emsp;&emsp;[4.13 Test the five possible outcomes #strategic `#new`](#-413-test-the-five-possible-outcomes)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#5-going-to-production-practices\">5. Going To Production Practices (19)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[5.1. Monitoring `#strategic`](#-51-monitoring)\u003C\u002Fbr>\n&emsp;&emsp;[5.2. Increase the observability using smart logging `#strategic`](#-52-increase-the-observability-using-smart-logging)\u003C\u002Fbr>\n&emsp;&emsp;[5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy `#strategic`](#-53-delegate-anything-possible-eg-gzip-ssl-to-a-reverse-proxy)\u003C\u002Fbr>\n&emsp;&emsp;[5.4. Lock dependencies](#-54-lock-dependencies)\u003C\u002Fbr>\n&emsp;&emsp;[5.5. Guard process uptime using the right tool](#-55-guard-process-uptime-using-the-right-tool)\u003C\u002Fbr>\n&emsp;&emsp;[5.6. Utilize all CPU cores](#-56-utilize-all-cpu-cores)\u003C\u002Fbr>\n&emsp;&emsp;[5.7. Create a ‘maintenance endpoint’](#-57-create-a-maintenance-endpoint)\u003C\u002Fbr>\n&emsp;&emsp;[5.8. Discover the unknowns using APM products `#advanced` `#updated`](#-58-discover-the-unknowns-using-apm-products)\u003C\u002Fbr>\n&emsp;&emsp;[5.9. Make your code production-ready](#-59-make-your-code-production-ready)\u003C\u002Fbr>\n&emsp;&emsp;[5.10. Measure and guard the memory usage `#advanced`](#-510-measure-and-guard-the-memory-usage)\u003C\u002Fbr>\n&emsp;&emsp;[5.11. Get your frontend assets out of Node](#-511-get-your-frontend-assets-out-of-node)\u003C\u002Fbr>\n&emsp;&emsp;[5.12. Strive to be stateless `#strategic`](#-512-strive-to-be-stateless)\u003C\u002Fbr>\n&emsp;&emsp;[5.13. Use tools that automatically detect vulnerabilities](#-513-use-tools-that-automatically-detect-vulnerabilities)\u003C\u002Fbr>\n&emsp;&emsp;[5.14. Assign a transaction id to each log statement `#advanced`](#-514-assign-a-transaction-id-to-each-log-statement)\u003C\u002Fbr>\n&emsp;&emsp;[5.15. Set NODE_ENV=production](#-515-set-node_envproduction)\u003C\u002Fbr>\n&emsp;&emsp;[5.16. Design automated, atomic and zero-downtime deployments `#advanced`](#-516-design-automated-atomic-and-zero-downtime-deployments)\u003C\u002Fbr>\n&emsp;&emsp;[5.17. Use an LTS release of Node.js](#-517-use-an-lts-release-of-nodejs)\u003C\u002Fbr>\n&emsp;&emsp;[5.18. Log to stdout, avoid specifying log destination within the app `#updated`](#-518-log-to-stdout-avoid-specifying-log-destination-within-the-app)\u003C\u002Fbr>\n&emsp;&emsp;[5.19. Install your packages with npm ci `#new`](#-519-install-your-packages-with-npm-ci)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#6-security-best-practices\">6. Security Practices (25)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[6.1. Embrace linter security rules](#-61-embrace-linter-security-rules)\u003C\u002Fbr>\n&emsp;&emsp;[6.2. Limit concurrent requests using a middleware](#-62-limit-concurrent-requests-using-a-middleware)\u003C\u002Fbr>\n&emsp;&emsp;[6.3 Extract secrets from config files or use packages to encrypt them `#strategic`](#-63-extract-secrets-from-config-files-or-use-packages-to-encrypt-them)\u003C\u002Fbr>\n&emsp;&emsp;[6.4. Prevent query injection vulnerabilities with ORM\u002FODM libraries `#strategic`](#-64-prevent-query-injection-vulnerabilities-with-ormodm-libraries)\u003C\u002Fbr>\n&emsp;&emsp;[6.5. Collection of generic security best practices](#-65-collection-of-generic-security-best-practices)\u003C\u002Fbr>\n&emsp;&emsp;[6.6. Adjust the HTTP response headers for enhanced security](#-66-adjust-the-http-response-headers-for-enhanced-security)\u003C\u002Fbr>\n&emsp;&emsp;[6.7. Constantly and automatically inspect for vulnerable dependencies `#strategic`](#-67-constantly-and-automatically-inspect-for-vulnerable-dependencies)\u003C\u002Fbr>\n&emsp;&emsp;[6.8. Protect Users' Passwords\u002FSecrets using bcrypt or scrypt `#strategic`](#-68-protect-users-passwordssecrets-using-bcrypt-or-scrypt)\u003C\u002Fbr>\n&emsp;&emsp;[6.9. Escape HTML, JS and CSS output](#-69-escape-html-js-and-css-output)\u003C\u002Fbr>\n&emsp;&emsp;[6.10. Validate incoming JSON schemas `#strategic`](#-610-validate-incoming-json-schemas)\u003C\u002Fbr>\n&emsp;&emsp;[6.11. Support blocklisting JWTs](#-611-support-blocklisting-jwts)\u003C\u002Fbr>\n&emsp;&emsp;[6.12. Prevent brute-force attacks against authorization `#advanced`](#-612-prevent-brute-force-attacks-against-authorization)\u003C\u002Fbr>\n&emsp;&emsp;[6.13. Run Node.js as non-root user](#-613-run-nodejs-as-non-root-user)\u003C\u002Fbr>\n&emsp;&emsp;[6.14. Limit payload size using a reverse-proxy or a middleware](#-614-limit-payload-size-using-a-reverse-proxy-or-a-middleware)\u003C\u002Fbr>\n&emsp;&emsp;[6.15. Avoid JavaScript eval statements](#-615-avoid-javascript-eval-statements)\u003C\u002Fbr>\n&emsp;&emsp;[6.16. Prevent evil RegEx from overloading your single thread execution](#-616-prevent-evil-regex-from-overloading-your-single-thread-execution)\u003C\u002Fbr>\n&emsp;&emsp;[6.17. Avoid module loading using a variable](#-617-avoid-module-loading-using-a-variable)\u003C\u002Fbr>\n&emsp;&emsp;[6.18. Run unsafe code in a sandbox](#-618-run-unsafe-code-in-a-sandbox)\u003C\u002Fbr>\n&emsp;&emsp;[6.19. Take extra care when working with child processes `#advanced`](#-619-take-extra-care-when-working-with-child-processes)\u003C\u002Fbr>\n&emsp;&emsp;[6.20. Hide error details from clients](#-620-hide-error-details-from-clients)\u003C\u002Fbr>\n&emsp;&emsp;[6.21. Configure 2FA for npm or Yarn `#strategic`](#-621-configure-2fa-for-npm-or-yarn)\u003C\u002Fbr>\n&emsp;&emsp;[6.22. Modify session middleware settings](#-622-modify-session-middleware-settings)\u003C\u002Fbr>\n&emsp;&emsp;[6.23. Avoid DOS attacks by explicitly setting when a process should crash `#advanced`](#-623-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash)\u003C\u002Fbr>\n&emsp;&emsp;[6.24. Prevent unsafe redirects](#-624-prevent-unsafe-redirects)\u003C\u002Fbr>\n&emsp;&emsp;[6.25. Avoid publishing secrets to the npm registry](#-625-avoid-publishing-secrets-to-the-npm-registry)\u003C\u002Fbr>\n&emsp;&emsp;[6.26. 6.26 Inspect for outdated packages](#-626-inspect-for-outdated-packages)\u003C\u002Fbr>\n&emsp;&emsp;[6.27. Import built-in modules using the 'node:' protocol `#new`](#-627-import-built-in-modules-using-the-node-protocol)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#7-draft-performance-best-practices\">7. Performance Practices (2) (Work In Progress️ ✍️)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[7.1. Don't block the event loop](#-71-dont-block-the-event-loop)\u003C\u002Fbr>\n&emsp;&emsp;[7.2. Prefer native JS methods over user-land utils like Lodash](#-72-prefer-native-js-methods-over-user-land-utils-like-lodash)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n  \u003Csummary>\n    \u003Ca href=\"#8-docker-best-practices\">8. Docker Practices (15)\u003C\u002Fa>\n  \u003C\u002Fsummary>\n\n&emsp;&emsp;[8.1 Use multi-stage builds for leaner and more secure Docker images `#strategic`](#-81-use-multi-stage-builds-for-leaner-and-more-secure-docker-images)\u003C\u002Fbr>\n&emsp;&emsp;[8.2. Bootstrap using node command, avoid npm start](#-82-bootstrap-using-node-command-avoid-npm-start)\u003C\u002Fbr>\n&emsp;&emsp;[8.3. Let the Docker runtime handle replication and uptime `#strategic`](#-83-let-the-docker-runtime-handle-replication-and-uptime)\u003C\u002Fbr>\n&emsp;&emsp;[8.4. Use .dockerignore to prevent leaking secrets](#-84-use-dockerignore-to-prevent-leaking-secrets)\u003C\u002Fbr>\n&emsp;&emsp;[8.5. Clean-up dependencies before production](#-85-clean-up-dependencies-before-production)\u003C\u002Fbr>\n&emsp;&emsp;[8.6. Shutdown smartly and gracefully `#advanced`](#-86-shutdown-smartly-and-gracefully)\u003C\u002Fbr>\n&emsp;&emsp;[8.7. Set memory limits using both Docker and v8 `#advanced` `#strategic`](#-87-set-memory-limits-using-both-docker-and-v8)\u003C\u002Fbr>\n&emsp;&emsp;[8.8. Plan for efficient caching](#-88-plan-for-efficient-caching)\u003C\u002Fbr>\n&emsp;&emsp;[8.9. Use explicit image reference, avoid latest tag](#-89-use-explicit-image-reference-avoid-latest-tag)\u003C\u002Fbr>\n&emsp;&emsp;[8.10. Prefer smaller Docker base images](#-810-prefer-smaller-docker-base-images)\u003C\u002Fbr>\n&emsp;&emsp;[8.11. Clean-out build-time secrets, avoid secrets in args `#strategic #new`](#-811-clean-out-build-time-secrets-avoid-secrets-in-args)\u003C\u002Fbr>\n&emsp;&emsp;[8.12. Scan images for multi layers of vulnerabilities `#advanced`](#-812-scan-images-for-multi-layers-of-vulnerabilities)\u003C\u002Fbr>\n&emsp;&emsp;[8.13 Clean NODE_MODULE cache](#-813-clean-node_module-cache)\u003C\u002Fbr>\n&emsp;&emsp;[8.14. Generic Docker practices](#-814-generic-docker-practices)\u003C\u002Fbr>\n&emsp;&emsp;[8.15. Lint your Dockerfile `#new`](#-815-lint-your-dockerfile)\u003C\u002Fbr>\n\n\u003C\u002Fdetails>\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n# `1. Project Architecture Practices`\n\n## ![✔] 1.1 Structure your solution by business components\n\n### `📝 #updated`\n\n**TL;DR:** The root of a system should contain folders or repositories that represent reasonably sized business modules. Each component represents a product domain (i.e., bounded context), like 'user-component', 'order-component', etc. Each component has its own API, logic, and logical database. What is the significant merit? With an autonomous component, every change is performed over a granular and smaller scope - the mental overload, development friction, and deployment fear are much smaller and better. As a result, developers can move much faster. This does not necessarily demand physical separation and can be achieved using a Monorepo or with a multi-repo\n\n```bash\nmy-system\n├─ apps (components)\n│  ├─ orders\n│  ├─ users\n│  ├─ payments\n├─ libraries (generic cross-component functionality)\n│  ├─ logger\n│  ├─ authenticator\n```\n\n**Otherwise:** when artifacts from various modules\u002Ftopics are mixed together, there are great chances of a tightly-coupled 'spaghetti' system. For example, in an architecture where 'module-a controller' might call 'module-b service', there are no clear modularity borders - every code change might affect anything else. With this approach, developers who code new features struggle to realize the scope and impact of their change. Consequently, they fear breaking other modules, and each deployment becomes slower and riskier\n\n🔗 [**Read More: structure by components**](.\u002Fsections\u002Fprojectstructre\u002Fbreakintcomponents.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 1.2 Layer your components with 3-tiers, keep the web layer within its boundaries\n\n### `📝 #updated`\n\n**TL;DR:** Each component should contain 'layers' - a dedicated folder for common concerns: 'entry-point' where controller lives, 'domain' where the logic lives, and 'data-access'. The primary principle of the most popular architectures is to separate the technical concerns (e.g., HTTP, DB, etc) from the pure logic of the app so a developer can code more features without worrying about infrastructural concerns. Putting each concern in a dedicated folder, also known as the [3-Tier pattern](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMultitier_architecture), is the _simplest_ way to meet this goal\n\n```bash\nmy-system\n├─ apps (components)\n│  ├─ component-a\n   │  ├─ entry-points\n   │  │  ├─ api # controller comes here\n   │  │  ├─ message-queue # message consumer comes here\n   │  ├─ domain # features and flows: DTO, services, logic\n   │  ├─ data-access # DB calls w\u002Fo ORM\n```\n\n**Otherwise:** It's often seen that developer pass web objects like request\u002Fresponse to functions in the domain\u002Flogic layer - this violates the separation principle and makes it harder to access later the logic code by other clients like testing code, scheduled jobs, message queues, etc\n\n🔗 [**Read More: layer your app**](.\u002Fsections\u002Fprojectstructre\u002Fcreatelayers.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 1.3 Wrap common utilities as packages, consider publishing\n\n**TL;DR:** Place all reusable modules in a dedicated folder, e.g., \"libraries\", and underneath each module in its own folder, e.g., \"\u002Flibraries\u002Flogger\". Make the module an independent package with its own package.json file to increase the module encapsulation, and allows future publishing to a repository. In a Monorepo setup, modules can be consumed by 'npm linking' to their physical paths, using ts-paths or by publishing and installing from a package manager repository like the npm registry\n\n```bash\nmy-system\n├─ apps (components)\n  │  ├─ component-a\n├─ libraries (generic cross-component functionality)\n│  ├─ logger\n│  │  ├─ package.json\n│  │  ├─ src\n│  │  │ ├─ index.js\n\n```\n\n**Otherwise:** Clients of a module might import and get coupled to internal functionality of a module. With a package.json at the root, one can set a package.json.main or package.json.exports to explicitly tell which files and functions are part of the public interface\n\n🔗 [**Read More: Structure by feature**](.\u002Fsections\u002Fprojectstructre\u002Fwraputilities.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 1.4 Use environment aware, secure and hierarchical config\n\n### `📝 #updated`\n\n**TL;DR:** A 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 (d) typing support (e) validation for failing fast (f) Specify default for each key. There are a few packages that can help tick most of those boxes like [convict](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fconvict), [env-var](https:\u002F\u002Fgithub.com\u002Fevanshortiss\u002Fenv-var), [zod](https:\u002F\u002Fgithub.com\u002Fcolinhacks\u002Fzod), and others\n\n**Otherwise:** Consider a mandatory environment variable that wasn't provided. The app starts successfully and serve requests, some information is already persisted to DB. Then, it's realized that without this mandatory key the request can't complete, leaving the app in a dirty state\n\n🔗 [**Read More: configuration best practices**](.\u002Fsections\u002Fprojectstructre\u002Fconfigguide.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 1.5 Consider all the consequences when choosing the main framework\n\n### `🌟 #new`\n\n**TL;DR:** When building apps and APIs, using a framework is mandatory. It's easy to overlook alternative frameworks or important considerations and then finally land on a sub optimal option. As of 2023\u002F2024, we believe that these four frameworks are worth considering: [Nest.js](https:\u002F\u002Fnestjs.com\u002F), [Fastify](https:\u002F\u002Fwww.fastify.io\u002F), [express](https:\u002F\u002Fexpressjs.com\u002F), and [Koa](https:\u002F\u002Fkoajs.com\u002F). Click read more below for a detailed pros\u002Fcons of each framework. Simplistically, we believe that Nest.js is the best match for teams who wish to go OOP and\u002For build large-scale apps that can't get partitioned into smaller _autonomous_ components. Fastify is our recommendation for apps with reasonably-sized components (e.g., Microservices) that are built around simple Node.js mechanics. Read our [full considerations guide here](.\u002Fsections\u002Fprojectstructre\u002Fchoose-framework.md)\n\n**Otherwise:** Due to the overwhelming amount of considerations, it's easy to make decisions based on partial information and compare apples with oranges. For example, it's believed that Fastify is a minimal web-server that should get compared with express only. In reality, it's a rich framework with many official plugins that cover many concerns\n\n🔗 [**Read More: Choosing the right framework**](.\u002Fsections\u002Fprojectstructre\u002Fchoose-framework.md)\n\n## ![✔] 1.6 Use TypeScript sparingly and thoughtfully\n\n### `🌟 #new`\n\n**TL;DR:** Coding without type safety is no longer an option, TypeScript is the most popular option for this mission. Use it to define variables and functions return types. With that, it is also a double edge sword that can greatly _encourage_ complexity with its additional ~ 50 keywords and sophisticated features. Consider using it sparingly, mostly with simple types, and utilize advanced features only when a real need arises\n\n**Otherwise:** [Researches](https:\u002F\u002Fearlbarr.com\u002Fpublications\u002Ftypestudy.pdf) show that using TypeScript can help in detecting ~20% bugs earlier. Without it, also the developer experience in the IDE is intolerable. On the flip side, 80% of other bugs were not discovered using types. Consequently, typed syntax is valuable but limited. Only efficient tests can discover the whole spectrum of bugs, including type-related bugs. It might also defeat its purpose: sophisticated code features are likely to increase the code complexity, which by itself increases both the amount of bugs and the average bug fix time\n\n🔗 [**Read More: TypeScript considerations**](.\u002Fsections\u002Fprojectstructre\u002Ftypescript-considerations.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\u003Cbr\u002F>\n\n\u003Cp align=\"right\">\u003Ca href=\"#table-of-contents\">⬆ Return to top\u003C\u002Fa>\u003C\u002Fp>\n\n# `2. Error Handling Practices`\n\n## ![✔] 2.1 Use Async-Await or promises for async error handling\n\n**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 Promises with async-await which enables a much more compact and familiar code syntax like try-catch\n\n**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\n\n🔗 [**Read More: avoiding callbacks**](.\u002Fsections\u002Ferrorhandling\u002Fasyncerrorhandling.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.2 Extend the built-in Error object\n\n### `📝 #updated`\n\n**TL;DR:** Some libraries throw errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Instead, create app error object\u002Fclass that extends the built-in Error object and use it whenever rejecting, throwing or emitting an error. The app error should add useful imperative properties like the error name\u002Fcode and isCatastrophic. By doing so, all errors have a unified structure and support better error handling. There is `no-throw-literal` ESLint rule that strictly checks that (although it has some [limitations](https:\u002F\u002Feslint.org\u002Fdocs\u002Frules\u002Fno-throw-literal) which can be solved when using TypeScript and setting the `@typescript-eslint\u002Fno-throw-literal` rule)\n\n**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!\n\n🔗 [**Read More: using the built-in error object**](.\u002Fsections\u002Ferrorhandling\u002Fuseonlythebuiltinerror.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.3 Distinguish catastrophic errors from operational errors\n\n### `📝 #updated`\n\n**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, catastrophic error (also known as programmer errors) refers to unusual code failures that dictate to gracefully restart the application\n\n**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 catastrophic 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\n\n🔗 [**Read More: operational vs programmer error**](.\u002Fsections\u002Ferrorhandling\u002Foperationalvsprogrammererror.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.4 Handle errors centrally, not within a middleware\n\n**TL;DR:** Error handling logic such as logging, deciding whether to crash and monitoring metrics should be encapsulated in a dedicated and centralized object that all entry-points (e.g. APIs, cron jobs, scheduled jobs) call when an error comes in\n\n**Otherwise:** Not handling errors within a single place will lead to code duplication and probably to improperly handled errors\n\n🔗 [**Read More: handling errors in a centralized place**](.\u002Fsections\u002Ferrorhandling\u002Fcentralizedhandling.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.5 Document API errors using OpenAPI or GraphQL\n\n**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 OpenAPI. If you're using GraphQL, you can utilize your schema and comments as well\n\n**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)\n\n🔗 [**Read More: documenting API errors in Swagger or GraphQL**](.\u002Fsections\u002Ferrorhandling\u002Fdocumentingusingswagger.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.6 Exit the process gracefully when a stranger comes to town\n\n**TL;DR:** When an unknown error occurs (catastrophic error, see best practice 2.3) - there is uncertainty about the application healthiness. In this case, there is no escape from making the error observable, shutting off connections and exiting the process. Any reputable runtime framework like Dockerized services or cloud serverless solutions will take care to restart\n\n**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\n\n🔗 [**Read More: shutting the process**](.\u002Fsections\u002Ferrorhandling\u002Fshuttingtheprocess.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.7 Use a mature logger to increase errors visibility\n\n### `📝 #updated`\n\n**TL;DR:** A robust logging tools like [Pino](https:\u002F\u002Fgithub.com\u002Fpinojs\u002Fpino) or [Winston](https:\u002F\u002Fgithub.com\u002Fwinstonjs\u002Fwinston) increases the errors visibility using features like log-levels, pretty print coloring and more. Console.log lacks these imperative features and should be avoided. The best in class logger allows attaching custom useful properties to log entries with minimized serialization performance penalty. Developers should write logs to `stdout` and let the infrastructure pipe the stream to the appropriate log aggregator\n\n**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\n\n🔗 [**Read More: using a mature logger**](.\u002Fsections\u002Ferrorhandling\u002Fusematurelogger.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.8 Test error flows using your favorite test framework\n\n### `📝 #updated`\n\n**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. On top of this, simulate deeper error flows like uncaught exceptions and ensure that the error handler treat these properly (see code examples within the \"read more\" section)\n\n**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\n\n🔗 [**Read More: testing error flows**](.\u002Fsections\u002Ferrorhandling\u002Ftestingerrorflows.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.9 Discover errors and downtime using APM products\n\n**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\n\n**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\n\n🔗 [**Read More: using APM products**](.\u002Fsections\u002Ferrorhandling\u002Fapmproducts.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.10 Catch unhandled promise rejections\n\n### `📝 #updated`\n\n**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle it. Even if your code is subscribed to `process.uncaughtException`! Overcome this by registering to the event `process.unhandledRejection`\n\n**Otherwise:** Your errors will get swallowed and leave no trace. Nothing to worry about\n\n🔗 [**Read More: catching unhandled promise rejection**](.\u002Fsections\u002Ferrorhandling\u002Fcatchunhandledpromiserejection.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.11 Fail fast, validate arguments using a dedicated library\n\n**TL;DR:** 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 modern validation library like [ajv](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fajv), [zod](https:\u002F\u002Fgithub.com\u002Fcolinhacks\u002Fzod), or [typebox](https:\u002F\u002Fgithub.com\u002Fsinclairzx81\u002Ftypebox)\n\n**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?\n\n🔗 [**Read More: failing fast**](.\u002Fsections\u002Ferrorhandling\u002Ffailfast.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.12 Always await promises before returning to avoid a partial stacktrace\n\n### `🌟 #new`\n\n**TL;DR:** Always do `return await` when returning a promise to benefit full error stacktrace. If a\nfunction returns a promise, that function must be declared as `async` function and explicitly\n`await` the promise before returning it\n\n**Otherwise:** The function that returns a promise without awaiting won't appear in the stacktrace.\nSuch missing frames would probably complicate the understanding of the flow that leads to the error,\nespecially if the cause of the abnormal behavior is inside of the missing function\n\n🔗 [**Read More: returning promises**](.\u002Fsections\u002Ferrorhandling\u002Freturningpromises.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 2.13 Subscribe to event emitters and streams 'error' event\n\n### `🌟 #new`\n\n**TL;DR:** Unlike typical functions, a try-catch clause won't get errors that originate from Event Emitters and anything inherited from it (e.g., streams). Instead of try-catch, subscribe to an event emitter's 'error' event so your code can handle the error in context. When dealing with [EventTargets](https:\u002F\u002Fnodejs.org\u002Fapi\u002Fevents.html#eventtarget-and-event-api) (the web standard version of Event Emitters) there are no 'error' event and all errors end in the process.on('error) global event - in this case, at least ensure that the process crash or not based on the desired context. Also, mind that error originating from _asynchronous_ event handlers are not get caught unless the event emitter is initialized with {captureRejections: true}\n\n**Otherwise:** Event emitters are commonly used for global and key application functionality such as DB or message queue connection. When this kind of crucial objects throw an error, at best the process will crash due to unhandled exception. Even worst, it will stay alive as a zombie while a key functionality is turned off\n\n\u003Cbr\u002F>\u003Cbr\u002F>\u003Cbr\u002F>\n\n\u003Cp align=\"right\">\u003Ca href=\"#table-of-contents\">⬆ Return to top\u003C\u002Fa>\u003C\u002Fp>\n\n# `3. Code Patterns And Style Practices`\n\n## ![✔] 3.1 Use ESLint\n\n**TL;DR:** [ESLint](https:\u002F\u002Feslint.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:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fprettier) are more powerful in formatting the fix and work in conjunction with ESLint\n\n**Otherwise:** Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking the project's code style\n\n🔗 [**Read More: Using ESLint and Prettier**](.\u002Fsections\u002Fcodestylepractices\u002Feslint_prettier.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.2 Use Node.js eslint extension plugins\n\n### `📝 #updated`\n\n**TL;DR:** On top of ESLint standard rules that cover vanilla JavaScript, add Node.js specific plugins like [eslint-plugin-node](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Feslint-plugin-node), [eslint-plugin-mocha](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Feslint-plugin-mocha) and [eslint-plugin-node-security](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Feslint-plugin-security), [eslint-plugin-require](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Feslint-plugin-require), [\u002Feslint-plugin-jest](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Feslint-plugin-jest) and other useful rules\n\n**Otherwise:** Many faulty Node.js code patterns might escape under the radar. For example, developers might require(variableAsPath) files with a variable given as a path which allows attackers to execute any JS script. Node.js linters can detect such patterns and complain early\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.3 Start a Codeblock's Curly Braces on the Same Line\n\n**TL;DR:** The opening curly braces of a code block should be on the same line as the opening statement\n\n### Code Example\n\n```javascript\n\u002F\u002F Do\nfunction someFunction() {\n  \u002F\u002F code block\n}\n\n\u002F\u002F Avoid\nfunction someFunction()\n{\n  \u002F\u002F code block\n}\n```\n\n**Otherwise:** Deferring from this best practice might lead to unexpected results, as seen in the StackOverflow thread below:\n\n🔗 [**Read more:** \"Why do results vary based on curly brace placement?\" (StackOverflow)](https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F3641519\u002Fwhy-does-a-results-vary-based-on-curly-brace-placement)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.4 Separate your statements properly\n\nNo 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.\n\n**TL;DR:** Use ESLint to gain awareness about separation concerns. [Prettier](https:\u002F\u002Fprettier.io\u002F) or [Standardjs](https:\u002F\u002Fstandardjs.com\u002F) can automatically resolve these issues.\n\n**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 immediately invoked function expressions to prevent most of the unexpected errors.\n\n### Code example\n\n```javascript\n\u002F\u002F Do\nfunction doThing() {\n    \u002F\u002F ...\n}\n\ndoThing()\n\n\u002F\u002F Do\n\nconst items = [1, 2, 3]\nitems.forEach(console.log)\n\n\u002F\u002F Avoid — throws exception\nconst m = new Map()\nconst a = [1,2,3]\n[...m.values()].forEach(console.log)\n> [...m.values()].forEach(console.log)\n>  ^^^\n> SyntaxError: Unexpected token ...\n\n\u002F\u002F Avoid — throws exception\nconst count = 2 \u002F\u002F it tries to run 2(), but 2 is not a function\n(function doSomething() {\n  \u002F\u002F do something amazing\n}())\n\u002F\u002F 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 altogether\n```\n\n🔗 [**Read more:** \"Semi ESLint rule\"](https:\u002F\u002Feslint.org\u002Fdocs\u002Frules\u002Fsemi)\n🔗 [**Read more:** \"No unexpected multiline ESLint rule\"](https:\u002F\u002Feslint.org\u002Fdocs\u002Frules\u002Fno-unexpected-multiline)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.5 Name your functions\n\n**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\n\n**Otherwise:** Debugging production issues using a core dump (memory snapshot) might become challenging as you notice significant memory consumption from anonymous functions\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.6 Use naming conventions for variables, constants, functions and classes\n\n**TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions, **_UpperCamelCase_** (capital first letter as well) when naming classes and **_UPPER_SNAKE_CASE_** when naming global or static variables. This will help you to easily distinguish between plain variables, functions, classes that require instantiation and variables declared at global module scope. Use descriptive names, but try to keep them short\n\n**Otherwise:** JavaScript is the only language in the world that allows invoking a constructor (\"Class\") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase\n\n### 3.6 Code Example\n\n```javascript\n\u002F\u002F for global variables names we use the const\u002Flet keyword and UPPER_SNAKE_CASE\nlet MUTABLE_GLOBAL = \"mutable value\";\nconst GLOBAL_CONSTANT = \"immutable value\";\nconst CONFIG = {\n  key: \"value\",\n};\n\n\u002F\u002F examples of UPPER_SNAKE_CASE convention in nodejs\u002Fjavascript ecosystem\n\u002F\u002F in javascript Math.PI module\nconst PI = 3.141592653589793;\n\n\u002F\u002F https:\u002F\u002Fgithub.com\u002Fnodejs\u002Fnode\u002Fblob\u002Fb9f36062d7b5c5039498e98d2f2c180dca2a7065\u002Flib\u002Finternal\u002Fhttp2\u002Fcore.js#L303\n\u002F\u002F in nodejs http2 module\nconst HTTP_STATUS_OK = 200;\nconst HTTP_STATUS_CREATED = 201;\n\n\u002F\u002F for class name we use UpperCamelCase\nclass SomeClassExample {\n  \u002F\u002F for static class properties we use UPPER_SNAKE_CASE\n  static STATIC_PROPERTY = \"value\";\n}\n\n\u002F\u002F for functions names we use lowerCamelCase\nfunction doSomething() {\n  \u002F\u002F for scoped variable names we use the const\u002Flet keyword and lowerCamelCase\n  const someConstExample = \"immutable value\";\n  let someMutableExample = \"mutable value\";\n}\n```\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.7 Prefer const over let. Ditch the var\n\n**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:\u002F\u002Fhackernoon.com\u002Fwhy-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have `const` and `let` at your disposal\n\n**Otherwise:** Debugging becomes way more cumbersome when following a variable that frequently changes\n\n🔗 [**Read more: JavaScript ES6+: var, let, or const?** ](https:\u002F\u002Fmedium.com\u002Fjavascript-scene\u002Fjavascript-es6-var-let-or-const-ba58b8dcde75)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.8 Require modules first, not inside functions\n\n**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\n\n**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 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\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.9 Set an explicit entry point to a module\u002Ffolder\n\n### `📝 #updated`\n\n**TL;DR:** When developing a module\u002Flibrary, set an explicit root file that exports the public and interesting code. Discourage the client code from importing deep files and becoming familiar with the internal structure. With commonjs (require), this can be done with an index.js file at the folder's root or the package.json.main field. With ESM (import), if a package.json exists on the root, the field \"exports\" allow specifying the module's root file. If no package.json exists, you may put an index.js file on the root which re-exports all the public functionality\n\n**Otherwise:** Having an explicit root file acts like a public 'interface' that encapsulates the internal, directs the caller to the public code and facilitates future changes without breaking the contract\n\n### 3.9 Code example - avoid coupling the client to the module structure\n\n```javascript\n\u002F\u002F Avoid: client has deep familiarity with the internals\n\n\u002F\u002F Client code\nconst SMSWithMedia = require(\".\u002FSMSProvider\u002Fproviders\u002Fmedia\u002Fmedia-provider.js\");\n\n\u002F\u002F Better: explicitly export the public functions\n\n\u002F\u002Findex.js, module code\nmodule.exports.SMSWithMedia = require(\".\u002FSMSProvider\u002Fproviders\u002Fmedia\u002Fmedia-provider.js\");\n\n\u002F\u002F Client code\nconst { SMSWithMedia } = require(\".\u002FSMSProvider\");\n```\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.10 Use the `===` operator\n\n**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\n\n**Otherwise:** Unequal variables might return true when compared with the `==` operator\n\n### 3.10 Code example\n\n```javascript\n\"\" == \"0\"; \u002F\u002F false\n0 == \"\"; \u002F\u002F true\n0 == \"0\"; \u002F\u002F true\n\nfalse == \"false\"; \u002F\u002F false\nfalse == \"0\"; \u002F\u002F true\n\nfalse == undefined; \u002F\u002F false\nfalse == null; \u002F\u002F false\nnull == undefined; \u002F\u002F true\n\n\" \\t\\r\\n \" == 0; \u002F\u002F true\n```\n\nAll statements above will return false if used with `===`\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.11 Use Async Await, avoid callbacks\n\n**TL;DR:** Async-await is the simplest way to express an asynchronous flow as it makes asynchronous code look synchronous. Async-await will also result in much more compact code and support for try-catch. This technique now supersedes callbacks and promises in _most_ cases. Using it in your code is probably the best gift one can give to the code reader\n\n**Otherwise:** Handling async errors in callback style are 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\n\n🔗[**Read more:** Guide to async-await 1.0](https:\u002F\u002Fgithub.com\u002Fyortus\u002Fasyncawait)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.12 Use arrow function expressions (=>)\n\n**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`)\n\n**Otherwise:** Longer code (in ES5 functions) is more prone to bugs and cumbersome to read\n\n🔗 [**Read more: It’s Time to Embrace Arrow Functions**](https:\u002F\u002Fmedium.com\u002Fjavascript-scene\u002Ffamiliarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 3.13 Avoid effects outside of functions\n\n### `🌟 #new`\n\n**TL;DR:** Avoid putting code with effects like network or DB calls outside of functions. Such a code will be executed immediately when another file requires the file. This 'floating' code might get executed when the underlying system is not ready yet. It also comes with a performance penalty even when this module's functions will finally not be used in runtime. Last, mocking these DB\u002Fnetwork calls for testing is harder outside of functions. Instead, put this code inside functions that should get called explicitly. If some DB\u002Fnetwork code must get executed right when the module loads, consider using the factory or revealing module patterns\n\n**Otherwise:** A typical web framework sets error handler, environment variables and monitoring. When DB\u002Fnetwork calls are made before the web framework is initialized, they won't be monitored or fail due to a lack of configuration data\n\n\u003Cbr\u002F>\u003Cbr\u002F>\u003Cbr\u002F>\n\n\u003Cp align=\"right\">\u003Ca href=\"#table-of-contents\">⬆ Return to top\u003C\u002Fa>\u003C\u002Fp>\n\n# `4. Testing And Overall Quality Practices`\n\n\\_We have dedicated guides for testing, see below. The best practices list here is a brief summary of these guides\n\na. [JavaScript testing best practices](https:\u002F\u002Fgithub.com\u002Fgoldbergyoni\u002Fjavascript-testing-best-practices)\nb. [Node.js testing - beyond the basics](https:\u002F\u002Fgithub.com\u002Ftestjavascript\u002Fnodejs-integration-tests-best-practices)\n\\_\n\n## ![✔] 4.1 At the very least, write API (component) testing\n\n**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:\u002F\u002Fwww.getpostman.com\u002F)). Afterwards, should you have more resources and time, continue with advanced test types like unit testing, DB testing, performance testing, etc\n\n**Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.2 Include 3 parts in each test name\n\n### `🌟 #new`\n\n**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\n\n**Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning?\n\n🔗 [**Read More: Include 3 parts in each test name**](.\u002Fsections\u002Ftestingandquality\u002F3-parts-in-name.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.3 Structure tests by the AAA pattern\n\n### `🌟 #new`\n\n**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\n\n**Otherwise:** Not only you spend long daily hours on understanding the main code, but now also what should have been the simple part of the day (testing) stretches your brain\n\n🔗 [**Read More: Structure tests by the AAA pattern**](.\u002Fsections\u002Ftestingandquality\u002Faaa.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.4 Ensure Node version is unified\n\n### `🌟 #new`\n\n**TL;DR:** Use tools that encourage or enforce the same Node.js version across different environments and developers. Tools like [nvm](https:\u002F\u002Fgithub.com\u002Fnvm-sh\u002Fnvm), and [Volta](https:\u002F\u002Fvolta.sh\u002F) allow specifying the project's version in a file so each team member can run a single command to conform with the project's version. Optionally, this definition can be replicated to CI and the production runtime (e.g., copy the specified value to .Dockerfile build and to the CI declaration file)\n\n**Otherwise:** A developer might face or miss an error because she uses a different Node.js version than her teammates. Even worse - the production runtime might be different than the environment where tests were executed\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.5 Avoid global test fixtures and seeds, add data per-test\n\n**TL;DR:** To prevent test 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\n\n**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\n\n🔗 [**Read More: Avoid global test fixtures**](.\u002Fsections\u002Ftestingandquality\u002Favoid-global-test-fixture.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.6 Tag your tests\n\n**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:\u002F\u002Fmochajs.org\u002F): mocha --grep 'sanity'\n\n**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\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.7 Check your test coverage, it helps to identify wrong test patterns\n\n**TL;DR:** Code coverage tools like [Istanbul](https:\u002F\u002Fgithub.com\u002Fistanbuljs\u002Fistanbuljs)\u002F[NYC](https:\u002F\u002Fgithub.com\u002Fistanbuljs\u002Fnyc) 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\n\n**Otherwise:** There won't be any automated metric telling you when a large portion of your code is not covered by testing\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.8 Use production-like environment for e2e testing\n\n**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 close to your real production environment as possible like a-continue (Missed -continue here, needs content. Judging by the **Otherwise** clause, this should mention docker-compose)\n\n**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\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.9 Refactor regularly using static analysis tools\n\n**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:\u002F\u002Fwww.sonarqube.org\u002F) (2,600+ [stars](https:\u002F\u002Fgithub.com\u002FSonarSource\u002Fsonarqube)) and [Code Climate](https:\u002F\u002Fcodeclimate.com\u002F) (1,500+ [stars](https:\u002F\u002Fgithub.com\u002Fcodeclimate\u002Fcodeclimate)).\n\n**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\n\n🔗 [**Read More: Refactoring!**](.\u002Fsections\u002Ftestingandquality\u002Frefactoring.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 4.10 Mock responses of external HTTP services\n\n### `🌟 #new`\n\n**TL;DR:** Use network mocking tools to simulate responses of external collaborators' services that are approached over the network (e.g., REST, Graph). This is imperative not only to isolate the component under test but mostly to simulate non-happy path flows. Tools like [nock](https:\u002F\u002Fgithub.com\u002Fnock\u002Fnock) (in-process) or [Mock-Server](https:\u002F\u002Fwww.mock-server.com\u002F) allow defining a specific response of external service in a single line of code. Remember to simulate also errors, delays, timeouts, and any other event that is likely to happen in production\n\n**Otherwise:** Allowing your component to reach real external services instances will likely result in naive tests that mostly cover happy paths. The tests might also be flaky and slow\n\n🔗 [**Read More: Mock external services**](.\u002Fsections\u002Ftestingandquality\u002Fmock-external-services.md)\n\n## ![✔] 4.11 Test your middlewares in isolation\n\n**TL;DR:** When a middleware holds some immense logic that spans many requests, it is worth testing it in isolation without waking up the entire web framework. This can be easily achieved by stubbing and spying on the {req, res, next} objects\n\n**Otherwise:** A bug in Express middleware === a bug in all or most requests\n\n🔗 [**Read More: Test middlewares in isolation**](.\u002Fsections\u002Ftestingandquality\u002Ftest-middlewares.md)\n\n## ![✔] 4.12 Specify a port in production, randomize in testing\n\n### `🌟 #new`\n\n**TL;DR:** When testing against the API, it's common and desirable to initialize the web server inside the tests. Let the server randomize the web server port in testing to prevent collisions. If you're using Node.js http server (used by most frameworks), doing so demands nothing but passing a port number zero - this will randomize an available port\n\n**Otherwise:** Specifying a fixed port will prevent two testing processes from running at the same time. Most of the modern test runners run with multiple processes by default\n\n🔗 [**Read More: Randomize a port for testing**](.\u002Fsections\u002Ftestingandquality\u002Frandomize-port.md)\n\n## ![✔] 4.13 Test the five possible outcomes\n\n### `🌟 #new`\n\n**TL;DR:** When testing a flow, ensure to cover five potential categories. Any time some action is triggered (e.g., API call), a reaction occurs, a meaningful **outcome** is produced and calls for testing. There are five possible outcome types for every flow: a response, a visible state change (e.g., DB), an outgoing API call, a new message in a queue, and an observability call (e.g., logging, metric). See a [checklist here](https:\u002F\u002Ftestjavascript.com\u002Fwp-content\u002Fuploads\u002F2021\u002F10\u002Fthe-backend-checklist.pdf). Each type of outcome comes with unique challenges and techniques to mitigate those challenges - we have a dedicated guide about this topic: [Node.js testing - beyond the basics](https:\u002F\u002Fgithub.com\u002Ftestjavascript\u002Fnodejs-integration-tests-best-practices)\n\n**Otherwise:** Consider a case when testing the addition of a new product to the system. It's common to see tests that assert on a valid response only. What if the product was failed to persist regardless of the positive response? what if when adding a new product demands calling some external service, or putting a message in the queue - shouldn't the test assert these outcomes as well? It's easy to overlook various paths, this is where a [checklist comes handy](https:\u002F\u002Ftestjavascript.com\u002Fwp-content\u002Fuploads\u002F2021\u002F10\u002Fthe-backend-checklist.pdf)\n\n🔗 [**Read More: Test five outcomes**](.\u002Fsections\u002Ftestingandquality\u002Ftest-five-outcomes.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\u003Cbr\u002F>\n\n\u003Cp align=\"right\">\u003Ca href=\"#table-of-contents\">⬆ Return to top\u003C\u002Fa>\u003C\u002Fp>\n\n# `5. Going To Production Practices`\n\n## ![✔] 5.1. Monitoring\n\n**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. In any case, the 4 layers of observability must be covered: uptime, metrics with focus on user-facing symptoms and Node.js technical metrics like event loop lag, distributed flows measurement with Open Telemetry and logging. Click ‘Read More’ below for an overview of the solutions\n\n**Otherwise:** Failure === disappointed customers. Simple\n\n🔗 [**Read More: Monitoring!**](.\u002Fsections\u002Fproduction\u002Fmonitoring.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.2. Increase the observability using smart logging\n\n**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\n\n**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\n\n🔗 [**Read More: Increase transparency using smart logging**](.\u002Fsections\u002Fproduction\u002Fsmartlogging.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy\n\n**TL;DR:** Node is quite bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use specialized infrastructure like nginx, HAproxy or cloud vendor services instead\n\n**Otherwise:** Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application core and performance will degrade accordingly\n\n🔗 [**Read More: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy**](.\u002Fsections\u002Fproduction\u002Fdelegatetoproxy.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.4. Lock dependencies\n\n**TL;DR:** Your code must be identical across all environments, but without a special lockfile npm lets dependencies drift across environments. Ensure to commit your package-lock.json so all the environments will be identical\n\n**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\n\n🔗 [**Read More: Lock dependencies**](.\u002Fsections\u002Fproduction\u002Flockdependencies.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.5. Guard process uptime using the right tool\n\n**TL;DR:** The process must go on and get restarted upon failures. Modern runtime platforms like Docker-ized platforms (e.g. Kubernetes), and Serverless take care for this automatically. When the app is hosted on a bare metal server, one must take care for a process management tools like [systemd](https:\u002F\u002Fsystemd.io\u002F). Avoid including a custom process management tool in a modern platform that monitors an app instance (e.g., Kubernetes) - doing so will hide failures from the infrastructure. When the underlying infrastructure is not aware of errors, it can't perform useful mitigation steps like re-placing the instance in a different location\n\n**Otherwise:** Running dozens of instances without a clear strategy and too many tools together (cluster management, docker, PM2) might lead to DevOps chaos\n\n🔗 [**Read More: Guard process uptime using the right tool**](.\u002Fsections\u002Fproduction\u002Fguardprocess.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.6. Utilize all CPU cores\n\n**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. Most of the modern run-times platform (e.g., Kubernetes) allow replicating instances of the app but they won't verify that all cores are utilized - this is your duty. If the app is hosted on a bare server, it's also your duty to use some process replication solution (e.g. systemd)\n\n**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!)\n\n🔗 [**Read More: Utilize all CPU cores**](.\u002Fsections\u002Fproduction\u002Futilizecpu.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.7. Create a ‘maintenance endpoint’\n\n**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-tested tools, some valuable information and operations are easier done using code\n\n**Otherwise:** You’ll find that you’re performing many “diagnostic deploys” – shipping code to production only to extract some information for diagnostic purposes\n\n🔗 [**Read More: Create a ‘maintenance endpoint’**](.\u002Fsections\u002Fproduction\u002Fcreatemaintenanceendpoint.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.8. Discover the unknowns using APM products\n\n### `📝 #updated`\n\n**TL;DR:** Consider adding another safety layer to the production stack - APM. While the majority of symptoms and causes can be detected using traditional monitoring techniques, in a distributed system there is more than meets the eye. Application monitoring and performance products (a.k.a. APM) can auto-magically go beyond traditional monitoring and provide additional layer of discovery and developer-experience. For example, some APM products can highlight a transaction that loads too slow on the **end-user's side** while suggesting the root cause. APMs also provide more context for developers who try to troubleshoot a log error by showing what was the server busy with when the error occurred. To name a few example\n\n**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\n\n🔗 [**Read More: Discover errors and downtime using APM products**](.\u002Fsections\u002Fproduction\u002Fapmproducts.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.9. Make your code production-ready\n\n**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 'Read More')\n\n**Otherwise:** A world champion IT\u002FDevOps guy won’t save a system that is badly written\n\n🔗 [**Read More: Make your code production-ready**](.\u002Fsections\u002Fproduction\u002Fproductioncode.md)\n\n\u003Cbr\u002F>\u003Cbr\u002F>\n\n## ![✔] 5.10. Measure and guard the memory usage\n\n**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 you","该项目是一个关于Node.js最佳实践的综合指南。它汇集了超过102条最佳实践，涵盖了ES6、ESLint、Express、Jest、Mocha等技术栈，并提供了详细的代码示例和引用资源。项目适合Node.js开发者在日常开发中参考以提高代码质量和可维护性，同时也适用于团队制定统一的编码规范和技术标准。通过持续更新，确保内容与最新的Node.js版本保持同步，帮助开发者紧跟技术发展趋势。","2026-06-17 02:34:03","top_all"]