{"id":47858,"date":"2026-08-13T18:09:29","date_gmt":"2026-08-13T16:09:29","guid":{"rendered":"\/mx\/tutoriales\/optimizacion-rendimiento-node-js\/"},"modified":"2026-08-13T18:09:29","modified_gmt":"2026-08-13T16:09:29","slug":"optimizacion-rendimiento-node-js","status":"publish","type":"post","link":"\/mx\/tutoriales\/optimizacion-rendimiento-node-js\/","title":{"rendered":"Optimizaci\u00f3n del rendimiento de Node.js: 12 formas de acelerar las apps"},"content":{"rendered":"<p class=\"wp-block-paragraph\">Optimizar el rendimiento de Node.js consiste en identificar y solucionar los aspectos de tu app que la ralentizan para que responda m&aacute;s r&aacute;pido, gestione m&aacute;s tr&aacute;fico, utilice los recursos de forma m&aacute;s eficiente y se mantenga estable bajo carga.<\/p><p class=\"wp-block-paragraph\">Lo mejor es medir primero y solucionar despu&eacute;s los problemas que indiquen los datos. Sin mediciones, no sabr&aacute;s si el problema es un bucle de eventos bloqueado, middleware que consume demasiados recursos, respuestas de API demasiado grandes, consultas repetidas a la base de datos, &iacute;ndices que faltan, fugas de memoria o tareas que consumen mucha CPU en el hilo principal.<\/p><p class=\"wp-block-paragraph\">Herramientas como los perfiladores, las herramientas de pruebas de carga y el software de APM permiten detectar los problemas reales de tu app.<\/p><p class=\"wp-block-paragraph\">Una vez que tengas una medici&oacute;n de referencia, c&eacute;ntrate en las soluciones que correspondan a los cuellos de botella detectados:<\/p><ol start=\"1\" class=\"wp-block-list\">\n<li>Usa c&oacute;digo as&iacute;ncrono para mantener libre el bucle de eventos<\/li>\n\n\n\n<li>Optimiza el middleware de Express y reduce el tama&ntilde;o de las respuestas de la API<\/li>\n\n\n\n<li>Almacena en cach&eacute; las consultas repetidas y los c&aacute;lculos que consumen muchos recursos<\/li>\n\n\n\n<li>Acelera las consultas a la base de datos con &iacute;ndices y connection pooling<\/li>\n\n\n\n<li>Usa streams en lugar de cargar archivos grandes en la memoria<\/li>\n\n\n\n<li>Saca las tareas que consumen mucha CPU del hilo principal<\/li>\n\n\n\n<li>Escala entre los n&uacute;cleos de la CPU mediante clustering<\/li>\n\n\n\n<li>Ajusta la configuraci&oacute;n de memoria y detecta las fugas<\/li>\n\n\n\n<li>Elimina las dependencias innecesarias<\/li>\n\n\n\n<li>Sirve archivos est&aacute;ticos a trav&eacute;s de una CDN con compresi&oacute;n<\/li>\n\n\n\n<li>Elige el entorno de hosting adecuado<\/li>\n\n\n\n<li>Supervisa continuamente el rendimiento en producci&oacute;n<\/li>\n<\/ol><p class=\"wp-block-paragraph\">La mayor&iacute;a de las apps no necesitan todas las optimizaciones a la vez. Soluciona primero los problemas que detectes al analizar el rendimiento, vuelve a medir y pasa al siguiente cuello de botella.<\/p><h2 class=\"wp-block-heading\" id=\"h-como-medir-el-rendimiento-de-node-js-antes-de-optimizarlo\">C&oacute;mo medir el rendimiento de Node.js antes de optimizarlo<\/h2><p class=\"wp-block-paragraph\">Medir el rendimiento de Node.js implica analizar el comportamiento de tu app bajo una carga realista, hacer un seguimiento de las m&eacute;tricas clave y comparar los resultados antes y despu&eacute;s de cada cambio.<\/p><p class=\"wp-block-paragraph\">Empieza con el perfilador integrado de Node.js y Chrome DevTools. Estas herramientas permiten comprobar si el c&oacute;digo que consume mucha CPU, la presi&oacute;n de memoria o los bloqueos del bucle de eventos est&aacute;n ralentizando la app.<\/p><p class=\"wp-block-paragraph\">Ejecuta el perfilador integrado con:<\/p><pre class=\"wp-block-preformatted\">node --prof app.js<br><br>node --prof-process isolate-*.log &gt; processed.txt<\/pre><p class=\"wp-block-paragraph\">Si prefieres un enfoque visual, inicia tu app con:<\/p><pre class=\"wp-block-preformatted\">node --inspect app.js<\/pre><p class=\"wp-block-paragraph\">A continuaci&oacute;n, abre <code>chrome:\/\/inspect<\/code> en Chrome.<\/p><p class=\"wp-block-paragraph\">Si necesitas un diagn&oacute;stico m&aacute;s claro, usa Clinic.js. Es un conjunto de herramientas gratuitas para detectar problemas de rendimiento en Node.js:<\/p><ul class=\"wp-block-list\">\n<li><strong>Clinic Doctor<\/strong> muestra si el problema est&aacute; relacionado con la CPU, la E\/S, la memoria o el bucle de eventos<\/li>\n\n\n\n<li><strong>Clinic Flame<\/strong> crea gr&aacute;ficos de llama para que puedas ver qu&eacute; funciones tardan m&aacute;s en ejecutarse<\/li>\n\n\n\n<li><strong>Clinic Bubbleprof<\/strong> te ayuda a detectar cadenas as&iacute;ncronas lentas<\/li>\n<\/ul><div class=\"wp-block-image wp-block-image aligncenter size-large\"><figure class=\"wp-lightbox-container\" data-wp-context='{\"imageId\":\"6a7e17c16b507\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a7e17c16b507\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/32\/2026\/08\/1778753978115-0-te-lo-digo-1.png\/public\" alt=\"P&aacute;gina de inicio de Clinic.js\" class=\"wp-image-55793\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">Una vez que hayas analizado el rendimiento, sabr&aacute;s qu&eacute; rutas, funciones u operaciones son lentas. Para comprobar c&oacute;mo se comportan bajo una carga elevada, haz una prueba de carga con una herramienta como Autocannon. Esta herramienta env&iacute;a un gran volumen de solicitudes a tu app y muestra los tiempos de respuesta, el n&uacute;mero de solicitudes y los errores.<\/p><p class=\"wp-block-paragraph\">Para obtener resultados &uacute;tiles de las pruebas de carga:<\/p><ul class=\"wp-block-list\">\n<li>Ejecuta las pruebas en hardware similar al de producci&oacute;n<\/li>\n\n\n\n<li>Deja que la app se caliente antes de hacer las mediciones<\/li>\n\n\n\n<li>Cambia solo una cosa cada vez<\/li>\n\n\n\n<li>Controla los l&iacute;mites de la base de datos y las API externas para evitar que distorsionen los resultados<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Una vez que tu app est&eacute; en producci&oacute;n, sigue haciendo mediciones. Las herramientas de APM como Datadog, New Relic o AppSignal miden la latencia de las rutas, los tiempos de las consultas a la base de datos, los errores y el uso de recursos con tr&aacute;fico real. Ayudan a detectar problemas en producci&oacute;n, pero no sustituyen a un an&aacute;lisis m&aacute;s detallado cuando necesitas inspeccionar cuellos de botella a nivel de c&oacute;digo.<\/p><p class=\"wp-block-paragraph\">Si tienes problemas de memoria, crea snapshots del heap con Chrome DevTools o <code>v8.writeHeapSnapshot()<\/code>. Los snapshots completos pueden consumir muchos recursos con tr&aacute;fico real, as&iacute; que cr&eacute;alos en un entorno de staging o en momentos de poco tr&aacute;fico.<\/p><p class=\"wp-block-paragraph\">Haz un seguimiento de estas m&eacute;tricas antes y despu&eacute;s de cada optimizaci&oacute;n:<\/p><figure tabindex=\"0\" class=\"wp-block-table\"><table><tbody><tr><td colspan=\"1\" rowspan=\"1\"><p><strong>M&eacute;trica<\/strong><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><strong>Qu&eacute; mide<\/strong><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><strong>Qu&eacute; ayuda a detectar<\/strong><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Tiempo de respuesta<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Duraci&oacute;n de la solicitud desde el principio hasta el final<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Rutas lentas, middleware que consume demasiados recursos<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Solicitudes por segundo<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Solicitudes gestionadas por segundo<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>L&iacute;mites de capacidad<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Uso de la CPU<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Tiempo de procesador que consume la app<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>C&oacute;digo que consume mucha CPU, bucles bloqueantes<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Uso de memoria (RSS)<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Memoria total que ocupa el proceso, incluidos los b&uacute;feres nativos<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Fugas de memoria, cach&eacute;s grandes, asignaciones nativas<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Retraso del bucle de eventos<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Retraso entre la ejecuci&oacute;n programada y la ejecuci&oacute;n real de las funciones de callback<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>C&oacute;digo s&iacute;ncrono bloqueante<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Tiempo de consulta de la base de datos<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Tiempo de respuesta de las consultas<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>&Iacute;ndices que faltan, consultas lentas<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Tasa de errores<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Porcentaje de solicitudes fallidas<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Tiempos de espera, rutas de c&oacute;digo inestables<\/span><\/p><\/td><\/tr><\/tbody><\/table><\/figure><h3 class=\"wp-block-heading\">&iquest;Cu&aacute;les son las m&eacute;tricas de rendimiento m&aacute;s importantes de Node.js?<\/h3><p class=\"wp-block-paragraph\">Las m&eacute;tricas m&aacute;s importantes son la latencia p95 y p99, el crecimiento de la memoria, el uso de la CPU, el retraso del bucle de eventos, la duraci&oacute;n de las consultas a la base de datos, la tasa de aciertos de la cach&eacute; y la tasa de errores.<\/p><p class=\"wp-block-paragraph\">El tiempo medio de respuesta es &uacute;til, pero puede ocultar problemas. Una ruta puede tener un tiempo medio de 200 ms mientras que las solicitudes del percentil 99 tardan tres segundos. Los valores p95 y p99 reflejan los retrasos que experimentan los usuarios con las solicitudes m&aacute;s lentas durante los picos de tr&aacute;fico, algo que los valores medios pueden ocultar.<\/p><p class=\"wp-block-paragraph\">Si la latencia p95 o p99 es alta, las dem&aacute;s m&eacute;tricas ayudan a identificar las posibles causas de las solicitudes lentas:<\/p><ul class=\"wp-block-list\">\n<li>Si la memoria sigue aumentando, puede haber una fuga<\/li>\n\n\n\n<li>Los picos de uso de la CPU apuntan a c&aacute;lculos intensivos en el hilo principal<\/li>\n\n\n\n<li>El retraso del bucle de eventos indica que hay c&oacute;digo bloqueante<\/li>\n\n\n\n<li>La duraci&oacute;n de las consultas a la base de datos y la tasa de aciertos de la cach&eacute; permiten detectar operaciones costosas que se ejecutan repetidamente<\/li>\n\n\n\n<li>Si la tasa de errores aumenta a medida que crece el tr&aacute;fico, es probable que a la app se le est&eacute;n agotando los recursos<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Revisa estas m&eacute;tricas con regularidad. Cuando cambie alguna, &uacute;sala para decidir qu&eacute; optimizaci&oacute;n aplicar a continuaci&oacute;n. Empieza por las correcciones a nivel de c&oacute;digo y, despu&eacute;s, pasa a la infraestructura y la monitorizaci&oacute;n seg&uacute;n sea necesario.<\/p><h2 class=\"wp-block-heading\" id=\"h-1-usa-codigo-asincrono-para-evitar-bloquear-el-bucle-de-eventos\">1. Usa c&oacute;digo as&iacute;ncrono para evitar bloquear el bucle de eventos<\/h2><p class=\"wp-block-paragraph\">El c&oacute;digo as&iacute;ncrono mantiene el bucle de eventos disponible mientras tu app espera a que terminen operaciones con archivos, consultas a bases de datos, peticiones de red o llamadas a API externas.<\/p><p class=\"wp-block-paragraph\"><a href=\"\/mx\/tutoriales\/que-es-node-js\/\">Node.js<\/a> ejecuta JavaScript en un &uacute;nico hilo principal. Cuando ese hilo est&aacute; ocupado con operaciones s&iacute;ncronas, las dem&aacute;s solicitudes quedan en espera. El c&oacute;digo bloqueante dentro de los controladores de solicitudes ralentiza toda la app.<\/p><p class=\"wp-block-paragraph\">Los bloqueos suelen deberse a llamadas s&iacute;ncronas o a c&aacute;lculos intensivos dentro de los controladores de solicitudes. Si el retraso del bucle de eventos es elevado, comprueba primero lo siguiente:<\/p><ul class=\"wp-block-list\">\n<li>Lecturas s&iacute;ncronas de archivos<\/li>\n\n\n\n<li>Bucles que requieren muchos recursos<\/li>\n\n\n\n<li>Procesamiento de grandes cantidades de datos JSON<\/li>\n\n\n\n<li>Cifrado s&iacute;ncrono<\/li>\n\n\n\n<li>Procesamiento que consume mucha CPU dentro de los controladores de solicitudes<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Compara la lectura bloqueante de un archivo con una versi&oacute;n as&iacute;ncrona:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Bloqueante: las dem&aacute;s peticiones quedan en espera\n\nconst data = fs.readFileSync('\/path\/to\/large-file.txt', 'utf8');\n\nres.send(data);\n\n\/\/ No bloqueante: el bucle de eventos sigue disponible\n\nconst data = await fs.promises.readFile('\/path\/to\/large-file.txt', 'utf8');\n\nres.send(data);<\/pre><p class=\"wp-block-paragraph\">La versi&oacute;n as&iacute;ncrona permite que Node gestione la lectura del archivo fuera del hilo principal de JavaScript. Mientras se lee el archivo, el bucle de eventos puede seguir gestionando otras peticiones.<\/p><p class=\"wp-block-paragraph\">Usa <code>async\/await<\/code> y las API de Node.js basadas en promesas, como <code>fs.promises<\/code>, de forma predeterminada.<\/p><p class=\"wp-block-paragraph\">Los controladores de bases de datos modernos como <code>pg<\/code>, <code>mysql2<\/code> y Mongoose funcionan de forma similar: gestionan la E\/S de forma as&iacute;ncrona, por lo que esperar una respuesta de la base de datos no suele bloquear el bucle de eventos. Sin embargo, los conjuntos de resultados grandes y el procesamiento intensivo de las respuestas s&iacute; pueden provocar bloqueos, as&iacute; que limita el tama&ntilde;o de las consultas y los datos devueltos.<\/p><p class=\"wp-block-paragraph\">El c&oacute;digo as&iacute;ncrono evita los bloqueos mientras se espera a que termine una operaci&oacute;n de E\/S, pero no soluciona las tareas que dependen de la CPU. Si una funci&oacute;n dedica 500 ms a realizar c&aacute;lculos, seguir&aacute; bloqueando el hilo principal aunque uses <code>await<\/code>. Los worker threads solucionan este problema ejecutando los c&aacute;lculos en otro hilo.<\/p><p class=\"wp-block-paragraph\">Si tu app usa llamadas s&iacute;ncronas dentro de los controladores de solicitudes, sustituirlas por versiones as&iacute;ncronas puede ser una de las formas m&aacute;s r&aacute;pidas de mejorar el rendimiento.<\/p><h2 class=\"wp-block-heading\" id=\"h-2-optimiza-el-middleware-de-express-y-las-respuestas-de-la-api\">2. Optimiza el middleware de Express y las respuestas de la API<\/h2><p class=\"wp-block-paragraph\">Optimizar la configuraci&oacute;n de Express y los datos que devuelve la API reduce el tiempo de respuesta al eliminar procesos que el servidor no deber&iacute;a ejecutar en cada solicitud.<\/p><p class=\"wp-block-paragraph\">El middleware aplicado con <code>app.use()<\/code> se ejecuta en todas las solicitudes que coincidan. Si la autenticaci&oacute;n, el registro, el an&aacute;lisis del cuerpo de las solicitudes, CORS, la limitaci&oacute;n de solicitudes y la compresi&oacute;n se aplican globalmente, algunas rutas pueden ejecutar procesos que no necesitan. Siempre que sea posible, aplica el middleware solo a las rutas que lo necesiten:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ En lugar de aplicar la autenticaci&oacute;n a todas las rutas\n\napp.use(authMiddleware);\n\n\/\/ Apl&iacute;cala solo donde sea necesaria\n\napp.get('\/dashboard', authMiddleware, dashboardHandler);\n\napp.get('\/public-page', publicHandler);<\/pre><p class=\"wp-block-paragraph\">Ahora, las rutas p&uacute;blicas omiten por completo el proceso de autenticaci&oacute;n.<\/p><p class=\"wp-block-paragraph\">A continuaci&oacute;n, revisa qu&eacute; datos acepta y devuelve la API. Establece un l&iacute;mite para el tama&ntilde;o de los datos JSON entrantes:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">app.use(express.json({ limit: '100kb' }));<\/pre><p class=\"wp-block-paragraph\">Ajusta el l&iacute;mite seg&uacute;n los datos que acepte realmente la API. En las respuestas, devuelve solo los campos que necesite el cliente. Enviar registros completos de la base de datos cuando el frontend solo utiliza tres campos consume tiempo de procesamiento y ancho de banda innecesariamente.<\/p><p class=\"wp-block-paragraph\">Pagina las respuestas grandes para evitar que los endpoints devuelvan miles de registros sin ning&uacute;n l&iacute;mite.<\/p><p class=\"wp-block-paragraph\">Si sirves archivos est&aacute;ticos a trav&eacute;s de Express, p&aacute;salos a una CDN o a un proxy inverso como Nginx. Si la CDN o el proxy inverso ya se encargan de la compresi&oacute;n, no uses <code>compression()<\/code> en Express. Comprime los archivos una sola vez y en una sola capa.<\/p><p class=\"wp-block-paragraph\">Aunque hayas optimizado todo esto, el tiempo de respuesta depende de toda la cadena de la solicitud: middleware, validaci&oacute;n, consultas a la base de datos, API externas, formateo de datos y transferencia de red. Analiza las rutas lentas para averiguar qu&eacute; parte provoca m&aacute;s retraso.<\/p><h3 class=\"wp-block-heading\">&iquest;C&oacute;mo puedes reducir el tiempo de respuesta de la API de Node.js?<\/h3><p class=\"wp-block-paragraph\">Puedes reducir el tiempo de respuesta de la API solucionando el punto m&aacute;s lento de cada ruta. Las medidas con mayor impacto son:<\/p><ul class=\"wp-block-list\">\n<li>Elimina el middleware innecesario de la ruta<\/li>\n\n\n\n<li>Devuelve solo los campos necesarios<\/li>\n\n\n\n<li>Pagina los resultados extensos<\/li>\n\n\n\n<li>Almacena en cach&eacute; las respuestas repetidas<\/li>\n\n\n\n<li>Optimiza las consultas a la base de datos<\/li>\n\n\n\n<li>Configura tiempos de espera para las peticiones externas lentas<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Si una ruta espera cinco segundos la respuesta de una API externa, establece un tiempo de espera y devuelve una respuesta alternativa cuando sea posible. As&iacute;, los usuarios reciben una respuesta controlada en lugar de tener que esperar a que falle la solicitud.<\/p><h2 class=\"wp-block-heading\" id=\"h-3-almacena-en-cache-los-datos-solicitados-con-mas-frecuencia\">3. Almacena en cach&eacute; los datos solicitados con m&aacute;s frecuencia<\/h2><p class=\"wp-block-paragraph\">La cach&eacute; reduce las consultas repetidas a la base de datos, las llamadas a API externas y los c&aacute;lculos que consumen muchos recursos. Si una consulta tarda 50 ms y devuelve el mismo resultado muchas veces, puedes ejecutarla una sola vez y atender las solicitudes posteriores desde la cach&eacute;.<\/p><p class=\"wp-block-paragraph\">Para valores peque&ntilde;os y de corta duraci&oacute;n en un solo servidor, suele bastar con una cach&eacute; sencilla en memoria. Lim&iacute;tala con un TTL o un tama&ntilde;o m&aacute;ximo para evitar que acabe causando problemas de memoria.<\/p><p class=\"wp-block-paragraph\">Usa Redis o Memcached cuando ejecutes varios procesos, necesites compartir la cach&eacute; entre servidores o quieras guardar los datos de sesi&oacute;n fuera del proceso de la app.<\/p><div class=\"wp-block-image wp-block-image aligncenter size-large\"><figure class=\"wp-lightbox-container\" data-wp-context='{\"imageId\":\"6a7e17c171602\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a7e17c171602\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/32\/2026\/08\/1778753985684-0-te-lo-cuento-1.png\/public\" alt=\"P&aacute;gina de inicio de Redis\" class=\"wp-image-55792\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><figure tabindex=\"0\" class=\"wp-block-table\"><table><tbody><tr><td colspan=\"1\" rowspan=\"1\"><p><strong>Tipo de almacenamiento en cach&eacute;<\/strong><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><strong>Ideal para<\/strong><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><strong>Ventaja principal<\/strong><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><strong>Ten cuidado con<\/strong><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>En memoria<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Valores peque&ntilde;os y temporales<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Lecturas r&aacute;pidas, sin conexi&oacute;n a Internet<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>No se comparte entre procesos<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Redis\/Memcached<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Datos compartidos, sesiones<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Funciona en todas las instancias<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>A&ntilde;ade un salto de red<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>CDN<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Archivos est&aacute;ticos, recursos p&uacute;blicos<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Menor carga en el servidor de origen y menor latencia<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Unos encabezados incorrectos pueden hacer que se sirvan archivos obsoletos<\/span><\/p><\/td><\/tr><tr><td colspan=\"1\" rowspan=\"1\"><p><span>Encabezados HTTP<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Visitas repetidas, recursos est&aacute;ticos<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Controlan c&oacute;mo se reutilizan las respuestas<\/span><\/p><\/td><td colspan=\"1\" rowspan=\"1\"><p><span>Unos encabezados mal configurados pueden almacenar en cach&eacute; m&aacute;s contenido del necesario<\/span><\/p><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Sea cual sea el tipo que uses, la cach&eacute; necesita dos ajustes: el TTL y la invalidaci&oacute;n.<\/p><p class=\"wp-block-paragraph\">El TTL (time to live) determina cu&aacute;nto tiempo se mantiene v&aacute;lido un valor almacenado en cach&eacute;. Un TTL corto mantiene los datos actualizados, pero implica repetir operaciones con m&aacute;s frecuencia. Un TTL largo mejora la velocidad, pero aumenta el riesgo de servir datos obsoletos. La invalidaci&oacute;n determina c&oacute;mo se eliminan o actualizan los valores almacenados en cach&eacute; cuando cambia la fuente.<\/p><p class=\"wp-block-paragraph\">Controla la tasa de aciertos de la cach&eacute;. Si el 90% de las solicitudes se atienden desde la cach&eacute;, la base de datos solo tendr&aacute; que gestionar el 10% de ese trabajo. Si la tasa de aciertos sigue siendo baja, puede que el TTL sea demasiado corto, que las claves de cach&eacute; sean demasiado espec&iacute;ficas o que los datos cambien con demasiada frecuencia para aprovechar bien la cach&eacute;.<\/p><h2 class=\"wp-block-heading\" id=\"h-4-optimiza-las-consultas-a-la-base-de-datos-y-la-gestion-de-las-conexiones\">4. Optimiza las consultas a la base de datos y la gesti&oacute;n de las conexiones<\/h2><p class=\"wp-block-paragraph\">Las consultas a la base de datos suelen ser una de las principales causas de las respuestas lentas de una API, ya que la app tiene que esperar a que la base de datos responda antes de poder devolver una respuesta.<\/p><p class=\"wp-block-paragraph\">Empieza por las soluciones con mayor impacto:<\/p><ul class=\"wp-block-list\">\n<li>Selecciona solo las columnas que necesites<\/li>\n\n\n\n<li>Evita <code>SELECT *<\/code><\/li>\n\n\n\n<li>A&ntilde;ade &iacute;ndices a las columnas que se usan con frecuencia para filtrar, ordenar o hacer joins<\/li>\n\n\n\n<li>Evita las consultas N+1<\/li>\n\n\n\n<li>Pagina los conjuntos de resultados grandes<\/li>\n\n\n\n<li>Usa connection pooling<\/li>\n\n\n\n<li>Revisa los planes de ejecuci&oacute;n de las consultas lentas<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Compara una consulta sin optimizar con otra m&aacute;s eficiente:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Lenta: recupera todas las columnas y todas las filas\n\nconst users = await db.query('SELECT * FROM users');\n\n\/\/ M&aacute;s r&aacute;pida: recupera solo los campos y las filas necesarios\n\nconst users = await db.query(\n\n'SELECT id, name, email FROM users ORDER BY created_at DESC LIMIT 20'\n\n);<\/pre><p class=\"wp-block-paragraph\">En una tabla con, por ejemplo, 100.000 filas y 30 columnas, la primera consulta hace que la app recupere y env&iacute;e muchos m&aacute;s datos de los necesarios. La segunda devuelve 20 filas con tres columnas. Con un &iacute;ndice adecuado en <code>created_at<\/code>, la base de datos puede recuperar los registros m&aacute;s recientes sin tener que escanear toda la tabla.<\/p><p class=\"wp-block-paragraph\">La consulta es solo una parte del proceso. Tambi&eacute;n importa c&oacute;mo se conecta la app a la base de datos. Sin connection pooling, la app abre una conexi&oacute;n nueva para cada solicitud, lo que a&ntilde;ade retraso y puede saturar la base de datos. Un pool mantiene las conexiones disponibles y las reutiliza.<\/p><p class=\"wp-block-paragraph\">La mayor&iacute;a de los controladores de Node.js, incluidos <code>pg<\/code> y <code>mysql2<\/code>, admiten connection pooling. Ajusta el tama&ntilde;o del pool en funci&oacute;n del tr&aacute;fico, la capacidad de la base de datos y el n&uacute;mero de instancias de la app. Si hay muy pocas conexiones, las solicitudes se acumulan en la cola. Si hay demasiadas, la base de datos puede sobrecargarse.<\/p><h3 class=\"wp-block-heading\">&iquest;C&oacute;mo mejoran los &iacute;ndices el rendimiento de las apps de Node.js?<\/h3><p class=\"wp-block-paragraph\">Los &iacute;ndices permiten que la base de datos encuentre m&aacute;s r&aacute;pido las filas que coinciden con una consulta, lo que reduce el tiempo de consulta y agiliza las respuestas de la API.<\/p><p class=\"wp-block-paragraph\">Si la ruta de inicio de sesi&oacute;n busca usuarios por email, por ejemplo, un &iacute;ndice en <code>email<\/code> ayuda a la base de datos a encontrar la fila correspondiente sin tener que revisar todos los registros:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">SELECT id, name, email\nFROM users\nWHERE email = $1;<\/pre><p class=\"wp-block-paragraph\">Los valores de email suelen ser &uacute;nicos o casi &uacute;nicos, por lo que este tipo de &iacute;ndice suele ser &uacute;til.<\/p><p class=\"wp-block-paragraph\">Para las consultas paginadas que filtran y ordenan datos, un &iacute;ndice compuesto como <code>(active, created_at)<\/code> puede ser &uacute;til, dependiendo de la base de datos y de c&oacute;mo est&eacute;n distribuidos los datos.<\/p><p class=\"wp-block-paragraph\">No indexes todas las columnas. Los &iacute;ndices aceleran las lecturas, pero aumentan el tiempo de escritura y ocupan espacio de almacenamiento, ya que la base de datos debe actualizar el &iacute;ndice cada vez que cambian las filas.<\/p><h2 class=\"wp-block-heading\" id=\"h-5-usa-streams-para-archivos-grandes-y-respuestas-de-gran-tamano\">5. Usa streams para archivos grandes y respuestas de gran tama&ntilde;o<\/h2><p class=\"wp-block-paragraph\">Los streams procesan los datos por partes en lugar de cargar archivos completos en la memoria. Por ejemplo, si cargas de la forma habitual un archivo CSV de 500 MB, ocupar&aacute; 500 MB de RAM. En cambio, al procesarlo mediante streams, solo se utiliza un peque&ntilde;o b&uacute;fer en cada momento.<\/p><p class=\"wp-block-paragraph\">Evita cargar archivos grandes de esta forma:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">app.get('\/download', async (req, res) =&gt; {\n\nconst data = await fs.promises.readFile('large-file.csv');\n\nres.send(data);\n\n});<\/pre><p class=\"wp-block-paragraph\">En su lugar, usa un stream:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const fs = require('node:fs');\n\nconst { pipeline } = require('node:stream\/promises');\n\napp.get('\/download', async (req, res, next) =&gt; {\n\ntry {\n\nawait pipeline(\n\nfs.createReadStream('large-file.csv'),\n\nres\n\n);\n\n} catch (err) {\n\nnext(err);\n\n}\n\n});<\/pre><p class=\"wp-block-paragraph\">La versi&oacute;n con streams empieza a enviar datos de inmediato y consume menos memoria, ya que Node procesa el archivo por partes.<\/p><p class=\"wp-block-paragraph\">Los streams tambi&eacute;n gestionan las diferencias de velocidad entre el emisor y el receptor mediante un mecanismo conocido como backpressure. Si la conexi&oacute;n del usuario es lenta, Node pausa la lectura hasta que el stream de respuesta pueda seguir procesando los datos. Usa <code>pipeline()<\/code> en producci&oacute;n, ya que gestiona mejor que <code>.pipe()<\/code> los errores de los streams y la liberaci&oacute;n de recursos.<\/p><p class=\"wp-block-paragraph\">En producci&oacute;n, comprueba tambi&eacute;n que el archivo exista, configura los encabezados adecuados y gestiona las desconexiones de los clientes.<\/p><h2 class=\"wp-block-heading\" id=\"h-6-reduce-las-tareas-que-consumen-mucha-cpu-en-el-hilo-principal\">6. Reduce las tareas que consumen mucha CPU en el hilo principal<\/h2><p class=\"wp-block-paragraph\">Las tareas que consumen mucha CPU bloquean el hilo principal e impiden que el bucle de eventos gestione otras solicitudes. El c&oacute;digo as&iacute;ncrono no soluciona este problema porque el motor de JavaScript sigue ejecutando los c&aacute;lculos en un solo hilo.<\/p><p class=\"wp-block-paragraph\">Entre las tareas que suelen consumir mucha CPU se encuentran:<\/p><ul class=\"wp-block-list\">\n<li>Procesamiento de im&aacute;genes<\/li>\n\n\n\n<li>Generaci&oacute;n de archivos PDF<\/li>\n\n\n\n<li>Cifrado<\/li>\n\n\n\n<li>Compresi&oacute;n<\/li>\n\n\n\n<li>Transformaci&oacute;n de grandes cantidades de datos JSON<\/li>\n\n\n\n<li>Generaci&oacute;n de informes<\/li>\n\n\n\n<li>C&aacute;lculos intensivos<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Saca las tareas que consumen muchos recursos del flujo principal de la solicitud en funci&oacute;n de cu&aacute;ndo y c&oacute;mo se necesite el resultado:<\/p><ul class=\"wp-block-list\">\n<li>Usa worker threads cuando el resultado se necesite durante la misma solicitud<\/li>\n\n\n\n<li>Usa colas de tareas en segundo plano cuando el procesamiento pueda completarse m&aacute;s tarde, por ejemplo, para generar informes o procesar emails<\/li>\n\n\n\n<li>Recurre a servicios externos cuando la carga de trabajo sea especializada o requiera muchos recursos, como el procesamiento de v&iacute;deo o el aprendizaje autom&aacute;tico<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Para las tareas en segundo plano, usa una cola como BullMQ con Redis para que la API pueda responder r&aacute;pidamente mientras otro worker procesa la tarea.<\/p><p class=\"wp-block-paragraph\">Para tareas web que consumen mucha CPU, como generar archivos PDF, cambiar el tama&ntilde;o de im&aacute;genes o transformar datos, los worker threads y las colas de tareas en segundo plano suelen permitirte seguir utilizando Node.js.<\/p><p class=\"wp-block-paragraph\">Para cargas de trabajo relacionadas con la ciencia de datos, el aprendizaje autom&aacute;tico o la computaci&oacute;n num&eacute;rica, puede merecer la pena comparar Node.js con Python antes de decidir d&oacute;nde ejecutar esa parte del sistema.<\/p><h3 class=\"wp-block-heading\">&iquest;Cu&aacute;ndo conviene usar worker threads en Node.js?<\/h3><p class=\"wp-block-paragraph\">Usa worker threads cuando tu app necesite ejecutar c&oacute;digo JavaScript que consuma mucha CPU sin bloquear el bucle de eventos principal y el resultado se necesite durante la misma solicitud.<\/p><p class=\"wp-block-paragraph\">Los worker threads y el clustering resuelven problemas distintos. Los worker threads permiten ejecutar tareas que consumen mucha CPU dentro de un mismo proceso sin bloquear el hilo principal. El clustering ejecuta varios procesos de Node.js para gestionar m&aacute;s solicitudes simult&aacute;neas entre los distintos n&uacute;cleos de la CPU.<\/p><p class=\"wp-block-paragraph\">Imagina que tu app genera facturas en PDF. El hilo principal puede seguir disponible mientras un worker se encarga de generarlas. En este ejemplo se crea un &uacute;nico worker para que resulte m&aacute;s sencillo entender el proceso. En producci&oacute;n, usa un pool de workers para las tareas recurrentes:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const { Worker } = require('node:worker_threads');\n\nfunction generatePDF(data) {\n\nreturn new Promise((resolve, reject) =&gt; {\n\nconst worker = new Worker('.\/pdf-worker.js', {\n\nworkerData: data,\n\n});\n\nworker.on('message', resolve);\n\nworker.on('error', reject);\n\nworker.on('exit', (code) =&gt; {\n\nif (code !== 0) {\n\nreject(new Error(`Worker stopped with exit code ${code}`));\n\n}\n\n});\n\n});\n\n}<\/pre><p class=\"wp-block-paragraph\">Crear un worker para cada tarea peque&ntilde;a puede consumir m&aacute;s recursos que la propia tarea. Para operaciones breves, de unos pocos milisegundos o menos, mantenlas en el hilo principal.<\/p><h2 class=\"wp-block-heading\" id=\"h-7-escala-node-js-mediante-clustering-y-balanceo-de-carga\">7. Escala Node.js mediante clustering y balanceo de carga<\/h2><p class=\"wp-block-paragraph\">El clustering ejecuta varios procesos worker de Node.js en distintos n&uacute;cleos de la CPU para que la app pueda gestionar m&aacute;s solicitudes simult&aacute;neas.<\/p><p class=\"wp-block-paragraph\">La mejora depender&aacute; de la carga de trabajo. Las apps con muchas operaciones de E\/S, como los servidores de API que esperan respuestas de bases de datos, suelen beneficiarse m&aacute;s que las apps con un uso intensivo de la CPU, ya que en estas &uacute;ltimas cada worker sigue compitiendo por los recursos de procesamiento.<\/p><p class=\"wp-block-paragraph\">En cualquier caso, casi nunca se consigue cuadruplicar el rendimiento con cuatro n&uacute;cleos, ya que los recursos compartidos, como la base de datos y la red, adem&aacute;s de la planificaci&oacute;n de procesos del sistema operativo, siguen imponiendo l&iacute;mites.<\/p><p class=\"wp-block-paragraph\">El m&oacute;dulo <code>cluster<\/code> de Node.js crea varios procesos de la app que comparten el mismo puerto. En la mayor&iacute;a de las plataformas, el proceso principal de Node distribuye las conexiones entre los workers mediante un sistema round-robin. PM2 simplifica este proceso al a&ntilde;adir gesti&oacute;n de procesos, reinicios autom&aacute;ticos, monitorizaci&oacute;n y recargas sin tiempo de inactividad.<\/p><p class=\"wp-block-paragraph\">M&aacute;s all&aacute; de un &uacute;nico servidor, un proxy inverso como Nginx o un balanceador de carga puede distribuir el tr&aacute;fico entre varios servidores o contenedores. Docker y Kubernetes permiten gestionar este tipo de despliegues a mayor escala.<\/p><div class=\"wp-block-image wp-block-image aligncenter size-large\"><figure class=\"wp-lightbox-container\" data-wp-context='{\"imageId\":\"6a7e17c177952\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a7e17c177952\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/32\/2026\/08\/1778753993383-0-te-lo-cuento-1.png\/public\" alt=\"P&aacute;gina de inicio de Nginx\" class=\"wp-image-55794\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">El clustering mejora la capacidad de la app para procesar solicitudes, pero no soluciona las consultas lentas, las fugas de memoria, las tareas que bloquean la CPU dentro de cada proceso ni la ausencia de cach&eacute;. Cuatro copias de una app lenta seguir&aacute;n siendo lentas, aunque puedan atender a m&aacute;s usuarios a la vez.<\/p><p>    <div class=\"announcement-block announcement-block--warning\">\n        <span class=\"announcement-block__heading\">\n            <svg width=\"24\" height=\"26\" viewBox=\"0 0 24 26\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n                d=\"M12 23.5C17.799 23.5 22.5 18.799 22.5 13C22.5 7.20101 17.799 2.5 12 2.5C6.20101 2.5 1.5 7.20101 1.5 13C1.5 18.799 6.20101 23.5 12 23.5ZM13.637 8.65198C13.637 7.74791 12.9041 7.01501 12 7.01501C11.0959 7.01501 10.363 7.74791 10.363 8.65198C10.5335 10.5375 10.875 14.383 10.875 14.383C10.875 15.0043 11.3787 15.508 12 15.508C12.6213 15.508 13.125 15.0043 13.125 14.383V14.38L13.637 8.65198ZM11.9927 16.714C11.3714 16.714 10.8677 17.2177 10.8677 17.839C10.8677 18.4603 11.3714 18.964 11.9927 18.964H12.0073C12.6286 18.964 13.1323 18.4603 13.1323 17.839C13.1323 17.2177 12.6286 16.714 12.0073 16.714H11.9927Z\"\n                fill=\"#BE1025\"\/>\n            <\/svg>\n            Warning        <\/span>\n        <p class=\"announcement-block__content\">\n            <strong>Advertencia<\/strong> Si los datos de sesi&oacute;n se almacenan &uacute;nicamente en la memoria del proceso, el clustering har&aacute; que las sesiones dejen de funcionar correctamente. Cada worker tiene su propia memoria, por lo que la siguiente solicitud de un usuario podr&iacute;a llegar a otro worker y hacer que pierda la sesi&oacute;n. Almacena las sesiones en Redis o en otro sistema de almacenamiento compartido.        <\/p>\n    <\/div>\n\n    \n\n\n\n<\/p><h3 class=\"wp-block-heading\">&iquest;Cu&aacute;l es la diferencia entre clustering y balanceo de carga?<\/h3><p class=\"wp-block-paragraph\">El clustering ejecuta varios procesos de Node.js en un mismo servidor para aprovechar m&aacute;s n&uacute;cleos de la CPU. El balanceo de carga distribuye el tr&aacute;fico entre procesos, servidores o contenedores.<\/p><p class=\"wp-block-paragraph\">Las apps en producci&oacute;n suelen usar ambas t&eacute;cnicas. El clustering permite aprovechar los n&uacute;cleos de la CPU de cada servidor, mientras que el balanceo de carga distribuye el tr&aacute;fico entre varios servidores para mejorar la disponibilidad y la capacidad.<\/p><h2 class=\"wp-block-heading\" id=\"h-8-optimiza-la-memoria-y-la-recoleccion-de-basura-de-node-js\">8. Optimiza la memoria y la recolecci&oacute;n de basura de Node.js<\/h2><p class=\"wp-block-paragraph\">Ajustar la memoria puede reducir las pausas de la recolecci&oacute;n de basura, evitar fallos y mantener la app estable con un tr&aacute;fico sostenido. La mayor&iacute;a de las apps no necesitan ajustes manuales de memoria a menos que surjan problemas relacionados con su uso.<\/p><p class=\"wp-block-paragraph\">V8, el motor de JavaScript que utiliza Node.js, gestiona la memoria autom&aacute;ticamente. Su heap incluye dos &aacute;reas principales:<\/p><ul class=\"wp-block-list\">\n<li><strong>New Space:<\/strong> almacena objetos de corta duraci&oacute;n y se libera con frecuencia<\/li>\n\n\n\n<li><strong>Old Space:<\/strong> almacena objetos que sobreviven a varios ciclos de recolecci&oacute;n de basura y se libera con menos frecuencia<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Un uso elevado de memoria no siempre indica una fuga. Puede deberse al crecimiento normal bajo carga, a cach&eacute;s grandes, a b&uacute;feres nativos o a la fragmentaci&oacute;n. Una fuga de memoria se produce cuando el uso de memoria sigue aumentando porque la app conserva referencias a objetos que ya no necesita.<\/p><p class=\"wp-block-paragraph\">Puedes ajustar los l&iacute;mites de memoria de V8 con:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">node --max-old-space-size=4096 app.js<\/pre><p class=\"wp-block-paragraph\">Este comando aumenta el l&iacute;mite de Old Space. &Uacute;salo cuando la app realmente necesite m&aacute;s espacio en el heap, no para ocultar una fuga de memoria. El valor predeterminado depende de la versi&oacute;n de Node.js y de la memoria disponible en el sistema. En los contenedores, Node.js ajusta el l&iacute;mite en funci&oacute;n de la memoria disponible para el contenedor.<\/p><p class=\"wp-block-paragraph\">El flag <code>--max-semi-space-size<\/code> influye en New Space. Un valor mayor reduce la frecuencia con la que los objetos de corta duraci&oacute;n pasan a Old Space, lo que puede reducir las ejecuciones m&aacute;s lentas de la recolecci&oacute;n de basura. Sin embargo, modificarlo sin analizar antes el rendimiento puede empeorarlo. Haz pruebas con tu carga de trabajo real antes de cambiarlo.<\/p><h3 class=\"wp-block-heading\">&iquest;C&oacute;mo puedes detectar fugas de memoria en Node.js?<\/h3><p class=\"wp-block-paragraph\">Las fugas de memoria se producen cuando la app conserva referencias a objetos que ya no necesita.<\/p><p class=\"wp-block-paragraph\">Entre las causas m&aacute;s habituales se encuentran:<\/p><ul class=\"wp-block-list\">\n<li>Arrays o mapas globales que no dejan de crecer<\/li>\n\n\n\n<li>Cach&eacute;s en memoria sin TTL ni l&iacute;mites de tama&ntilde;o<\/li>\n\n\n\n<li>Event listeners que nunca se eliminan<\/li>\n\n\n\n<li>Objetos grandes almacenados en closures<\/li>\n\n\n\n<li>Temporizadores que nunca se eliminan<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Usa snapshots del heap para comparar el uso de memoria a lo largo del tiempo:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const v8 = require('node:v8');\n\nv8.writeHeapSnapshot();<\/pre><p class=\"wp-block-paragraph\">Haz un snapshot, ejecuta la app bajo carga y haz otro despu&eacute;s. Los objetos cuyo n&uacute;mero sigue aumentando entre ambos snapshots pueden ser indicios de una fuga de memoria.<\/p><p class=\"wp-block-paragraph\">Supervisa tambi&eacute;n la memoria en producci&oacute;n. Si aumenta durante horas o d&iacute;as y no disminuye despu&eacute;s de la recolecci&oacute;n de basura, investiga la causa. Las pruebas de carga con Autocannon pueden hacer que las fugas aparezcan m&aacute;s r&aacute;pido en un entorno de staging.<\/p><h2 class=\"wp-block-heading\" id=\"h-9-reduce-la-sobrecarga-de-las-dependencias-y-el-codigo\">9. Reduce la sobrecarga de las dependencias y el c&oacute;digo<\/h2><p class=\"wp-block-paragraph\">Eliminar dependencias innecesarias y operaciones repetidas puede hacer que la app se inicie m&aacute;s r&aacute;pido, consuma menos memoria y reduzca los riesgos de seguridad. Muchas de estas mejoras son peque&ntilde;as tareas de limpieza, no requieren reescribir el c&oacute;digo.<\/p><p class=\"wp-block-paragraph\">Comprueba primero <code>package.json<\/code>. Elimina los paquetes que la app ya no utilice y busca paquetes grandes que solo se usen para tareas sencillas. Si utilizas Lodash &uacute;nicamente para <code>_.get()<\/code>, el encadenamiento opcional puede ser suficiente:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const city = user?.address?.city;<\/pre><p class=\"wp-block-paragraph\">Si utilizas Moment.js &uacute;nicamente para aplicar un formato b&aacute;sico a las fechas, <code>Intl.DateTimeFormat<\/code> o una biblioteca m&aacute;s peque&ntilde;a como <code>date-fns<\/code> pueden cubrir tus necesidades.<\/p><p class=\"wp-block-paragraph\">Las dependencias no son la &uacute;nica fuente de operaciones innecesarias. Tu propio c&oacute;digo tambi&eacute;n puede repetir operaciones que consumen muchos recursos:<\/p><ul class=\"wp-block-list\">\n<li>Crear un nuevo cliente HTTP para cada solicitud saliente<\/li>\n\n\n\n<li>Leer y analizar el mismo archivo de configuraci&oacute;n en cada solicitud<\/li>\n\n\n\n<li>Compilar una expresi&oacute;n regular dentro de un bucle<\/li>\n<\/ul><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Ineficiente: vuelve a leer la configuraci&oacute;n en cada solicitud\n\napp.get('\/settings', async (req, res) =&gt; {\n  const config = JSON.parse(await fs.promises.readFile('config.json', 'utf8'));\n\n  res.json({ theme: config.theme });\n});\n\n\/\/ Mejor: lee la configuraci&oacute;n una vez al iniciar la app\n\nconst config = JSON.parse(fs.readFileSync('config.json', 'utf8'));\n\napp.get('\/settings', (req, res) =&gt; {\n  res.json({ theme: config.theme });\n});<\/pre><p class=\"wp-block-paragraph\">Las lecturas s&iacute;ncronas no suponen un problema durante el inicio de la app porque todav&iacute;a no se est&aacute;n gestionando solicitudes. El problema aparece cuando se ejecutan dentro de los controladores de solicitudes, donde pueden bloquear otras solicitudes.<\/p><p class=\"wp-block-paragraph\">Mant&eacute;n actualizadas las dependencias que utilices. Las versiones m&aacute;s recientes suelen incluir mejoras de rendimiento y parches de seguridad.<\/p><h2 class=\"wp-block-heading\" id=\"h-10-usa-una-cdn-y-compresion-para-los-archivos-estaticos\">10. Usa una CDN y compresi&oacute;n para los archivos est&aacute;ticos<\/h2><p class=\"wp-block-paragraph\">Una CDN sirve archivos est&aacute;ticos desde ubicaciones m&aacute;s cercanas a los usuarios, lo que reduce la latencia y la carga del servidor de origen. &Uacute;sala para JavaScript, CSS, im&aacute;genes, fuentes y descargas est&aacute;ticas. Tu app de Node.js no deber&iacute;a dedicar recursos de la CPU a servir estos archivos cuando una CDN o un proxy inverso pueden encargarse de ellos.<\/p><p class=\"wp-block-paragraph\">Adem&aacute;s de la ubicaci&oacute;n, el tama&ntilde;o de los archivos tambi&eacute;n influye en la velocidad de carga. La compresi&oacute;n reduce su tama&ntilde;o antes de que lleguen al navegador. Gzip y Brotli son las principales opciones.<\/p><p class=\"wp-block-paragraph\">Brotli comprime mejor los archivos est&aacute;ticos que Gzip cuando se comprimen previamente durante el proceso de compilaci&oacute;n. Para las respuestas din&aacute;micas que se comprimen sobre la marcha, Gzip suele ser m&aacute;s r&aacute;pido porque la codificaci&oacute;n con Brotli consume m&aacute;s CPU.<\/p><p class=\"wp-block-paragraph\">Comprime archivos basados en texto como HTML, CSS, JavaScript, JSON y SVG. Evita comprimir archivos que ya utilizan formatos comprimidos, como JPEG, PNG, MP4 y ZIP, ya que el proceso consume CPU sin reducir demasiado su tama&ntilde;o.<\/p><p class=\"wp-block-paragraph\">Para las im&aacute;genes, usa formatos modernos como WebP o AVIF siempre que sea posible y ajusta sus dimensiones al tama&ntilde;o en el que realmente se muestran. Si subes una imagen de 4000 &times; 3000 pero la muestras a 400 &times; 300, el navegador seguir&aacute; descargando el archivo completo a menos que sirvas una versi&oacute;n m&aacute;s peque&ntilde;a. Redimensionar las im&aacute;genes durante la compilaci&oacute;n o mediante una CDN permite ahorrar ancho de banda.<\/p><p class=\"wp-block-paragraph\">Cuando los archivos est&eacute;n comprimidos y tengan el tama&ntilde;o adecuado, configura encabezados de cach&eacute; de larga duraci&oacute;n para evitar que los visitantes recurrentes tengan que descargarlos de nuevo:<\/p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Cache-Control: public, max-age=31536000, immutable<\/pre><p class=\"wp-block-paragraph\">Usa nombres de archivo con versionado para invalidar la cach&eacute;, como <code>app.a3f2b1.js<\/code>. As&iacute;, los navegadores pueden mantener los archivos en cach&eacute; durante mucho tiempo y seguir recibiendo las versiones actualizadas cuando cambie el nombre del archivo.<\/p><h2 class=\"wp-block-heading\" id=\"h-11-elige-el-entorno-de-hosting-adecuado-para-optimizar-el-rendimiento-de-node-js\">11. Elige el entorno de hosting adecuado para optimizar el rendimiento de Node.js<\/h2><p class=\"wp-block-paragraph\">El hosting influye en el rendimiento porque la CPU, la RAM, la velocidad del almacenamiento, el ancho de banda, el acceso a una CDN y la regi&oacute;n del servidor determinan c&oacute;mo funciona la app optimizada en producci&oacute;n.<\/p><p class=\"wp-block-paragraph\">Optimizar el c&oacute;digo hace que la app sea m&aacute;s r&aacute;pida. Elegir el hosting adecuado permite que ese rendimiento llegue a los usuarios. Ambos aspectos son necesarios.<\/p><p class=\"wp-block-paragraph\">La decisi&oacute;n principal es cu&aacute;nta infraestructura quieres gestionar.<\/p><figure tabindex=\"0\" class=\"wp-block-table\"><table><thead><tr><th>Factor<\/th><th>Hosting administrado de Node.js<\/th><th>VPS<\/th><\/tr><\/thead><tbody><tr><td><strong>Control del servidor<\/strong><\/td><td>La plataforma se encarga de la mayor parte de la configuraci&oacute;n<\/td><td>Acceso root completo<\/td><\/tr><tr><td><strong>Despliegue<\/strong><\/td><td>Mediante Git o archivos, con menor complejidad<\/td><td>SSH y configuraci&oacute;n manual<\/td><\/tr><tr><td><strong>Mantenimiento<\/strong><\/td><td>Lo gestiona el proveedor<\/td><td>T&uacute; te encargas de las actualizaciones y los parches<\/td><\/tr><tr><td><strong>Flexibilidad<\/strong><\/td><td>Funciona dentro de los l&iacute;mites de la plataforma<\/td><td>Control total sobre el entorno de ejecuci&oacute;n y el servidor<\/td><\/tr><tr><td><strong>Ideal para<\/strong><\/td><td>Apps est&aacute;ndar y despliegues m&aacute;s r&aacute;pidos<\/td><td>Stacks personalizados, Docker, PM2 y Nginx<\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">El <a href=\"\/mx\/hosting-apps-web\">hosting para Node.js<\/a> de Hostinger es una opci&oacute;n administrada. Permite desplegar proyectos mediante GitHub e incluye CDN, SSL y protecci&oacute;n DDoS, para que puedas centrarte en publicar el c&oacute;digo en lugar de mantener el servidor. El hosting para Node.js est&aacute; disponible en los planes Business y Cloud.<\/p><div class=\"wp-block-image wp-block-image aligncenter size-large\"><figure class=\"wp-lightbox-container\" data-wp-context='{\"imageId\":\"6a7e17c17ecaa\"}' data-wp-interactive=\"core\/image\" data-wp-key=\"6a7e17c17ecaa\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/32\/2026\/08\/1778754001399-0-te-lo-cuento-1.png\/public\" alt=\"Hostinger Node.js web app landing page\" class=\"wp-image-55795\"><button class=\"lightbox-trigger\" type=\"button\" aria-haspopup=\"dialog\" data-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\" data-wp-init=\"callbacks.initTriggerButton\" data-wp-on--click=\"actions.showLightbox\" data-wp-style--right=\"state.thisImage.buttonRight\" data-wp-style--top=\"state.thisImage.buttonTop\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewbox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\"><\/path>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure><\/div><p class=\"wp-block-paragraph\">El hosting VPS es m&aacute;s adecuado cuando necesitas acceso root, flujos de trabajo con Docker, PM2, Nginx, versiones espec&iacute;ficas de Node.js o ajustes de rendimiento de bajo nivel. A cambio, tendr&aacute;s que encargarte de las actualizaciones, los parches y la seguridad.<\/p><p class=\"wp-block-paragraph\">Puedes desplegar una app de Node.js con cualquiera de las dos opciones. Elige seg&uacute;n las necesidades de la app, no solo por el precio. La regi&oacute;n del servidor, los l&iacute;mites de CPU, la memoria, el escalado y la monitorizaci&oacute;n influyen en la experiencia de los usuarios.<\/p><figure class=\"wp-block-image size-large\"><a href=\"\/mx\/servidor-vps\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"300\" src=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/39\/2023\/02\/ES-VPS-hosting_in-text-banner.png\/w=1024,h=1024,fit=scale-down\" alt=\"\" class=\"wp-image-29287\" srcset=\"https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/39\/2023\/02\/ES-VPS-hosting_in-text-banner.png\/w=1024,fit=scale-down 1024w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/39\/2023\/02\/ES-VPS-hosting_in-text-banner.png\/w=300,fit=scale-down 300w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/39\/2023\/02\/ES-VPS-hosting_in-text-banner.png\/w=150,fit=scale-down 150w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/39\/2023\/02\/ES-VPS-hosting_in-text-banner.png\/w=768,fit=scale-down 768w, https:\/\/imagedelivery.net\/LqiWLm-3MGbYHtFuUbcBtA\/wp-content\/uploads\/sites\/39\/2023\/02\/ES-VPS-hosting_in-text-banner.png\/w=1536,fit=scale-down 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure><h2 class=\"wp-block-heading\" id=\"h-12-supervisa-el-rendimiento-de-node-js-en-produccion\">12. Supervisa el rendimiento de Node.js en producci&oacute;n<\/h2><p class=\"wp-block-paragraph\">La monitorizaci&oacute;n en producci&oacute;n permite detectar problemas que pueden pasar desapercibidos durante las pruebas de desarrollo, como solicitudes lentas con tr&aacute;fico real, fugas de memoria, picos de errores y consultas a la base de datos que se ralentizan a medida que aumenta el volumen de datos.<\/p><p class=\"wp-block-paragraph\">Las herramientas de APM como Datadog, New Relic o AppSignal permiten monitorizar el rendimiento de las rutas con tr&aacute;fico real. Por s&iacute; solas no detectan todos los problemas, as&iacute; que comb&iacute;nalas con registros estructurados, trazas, monitorizaci&oacute;n de errores y comprobaciones de disponibilidad.<\/p><p class=\"wp-block-paragraph\">Para configuraciones m&aacute;s sencillas, los registros estructurados con Pino o Winston, junto con la monitorizaci&oacute;n de disponibilidad, cubren las necesidades b&aacute;sicas.<\/p><p class=\"wp-block-paragraph\">Configura alertas cuando:<\/p><ul class=\"wp-block-list\">\n<li>Aumente la latencia p95 o p99<\/li>\n\n\n\n<li>La memoria aumente de forma continua<\/li>\n\n\n\n<li>El uso de la CPU se mantenga elevado<\/li>\n\n\n\n<li>Aumente la tasa de errores<\/li>\n\n\n\n<li>Aumente el tiempo de las consultas a la base de datos<\/li>\n\n\n\n<li>Disminuya la tasa de aciertos de la cach&eacute;<\/li>\n<\/ul><p class=\"wp-block-paragraph\">Empieza con umbrales conservadores y aj&uacute;stalos a medida que conozcas los patrones habituales de la app. Si las alertas generan demasiado ruido, acabar&aacute;n ignor&aacute;ndose. Las alertas bien definidas permiten detectar los problemas a tiempo.<\/p><p class=\"wp-block-paragraph\">Cuando las m&eacute;tricas indiquen que algo est&aacute; ralentizando la app, aplica la soluci&oacute;n correspondiente y vuelve a medir.<\/p><h2 class=\"wp-block-heading\" id=\"h-lista-de-comprobacion-para-optimizar-el-rendimiento-de-node-js\">Lista de comprobaci&oacute;n para optimizar el rendimiento de Node.js<\/h2><p class=\"wp-block-paragraph\">Usa esta lista despu&eacute;s de analizar el rendimiento de tu app. Empieza por los puntos relacionados con los cuellos de botella que hayas detectado y revisa el resto a medida que cambien el tr&aacute;fico, las funcionalidades y la infraestructura:<\/p><ul class=\"wp-block-list\">\n<li>Mide el rendimiento de referencia antes de modificar el c&oacute;digo<\/li>\n\n\n\n<li>Analiza las rutas lentas para detectar qu&eacute; las est&aacute; ralentizando<\/li>\n\n\n\n<li>Comprueba la latencia p95 y p99, no solo los valores medios<\/li>\n\n\n\n<li>Sustituye las operaciones s&iacute;ncronas dentro de los controladores de solicitudes<\/li>\n\n\n\n<li>Saca el middleware espec&iacute;fico de cada ruta de la configuraci&oacute;n global<\/li>\n\n\n\n<li>Limita el tama&ntilde;o de los datos JSON entrantes<\/li>\n\n\n\n<li>Devuelve solo los campos que necesita cada endpoint<\/li>\n\n\n\n<li>Pagina las respuestas con listas grandes<\/li>\n\n\n\n<li>Comprime las respuestas basadas en texto en una sola capa<\/li>\n\n\n\n<li>Almacena en cach&eacute; las consultas repetidas y los c&aacute;lculos que consumen muchos recursos<\/li>\n\n\n\n<li>Controla la tasa de aciertos de la cach&eacute;<\/li>\n\n\n\n<li>A&ntilde;ade &iacute;ndices para los filtros, joins y ordenaciones frecuentes<\/li>\n\n\n\n<li>Evita las consultas N+1<\/li>\n\n\n\n<li>Usa connection pooling para la base de datos<\/li>\n\n\n\n<li>Usa streams para cargas, descargas y exportaciones de gran tama&ntilde;o<\/li>\n\n\n\n<li>Traslada las tareas que consumen mucha CPU a worker threads o colas de tareas en segundo plano<\/li>\n\n\n\n<li>Escala entre los n&uacute;cleos de la CPU mediante clustering<\/li>\n\n\n\n<li>Almacena las sesiones en un sistema compartido cuando uses clustering<\/li>\n\n\n\n<li>Comprueba el crecimiento de la memoria antes de ajustar los flags del heap<\/li>\n\n\n\n<li>Elimina las dependencias que no utilices<\/li>\n\n\n\n<li>Sirve los archivos est&aacute;ticos mediante una CDN o un proxy inverso<\/li>\n\n\n\n<li>Supervisa la latencia, los errores, la CPU, la memoria, los tiempos de las consultas a la base de datos y el rendimiento de la cach&eacute;<\/li>\n<\/ul><h2 class=\"wp-block-heading\" id=\"h-que-hacer-despues-de-optimizar-node-js\">Qu&eacute; hacer despu&eacute;s de optimizar Node.js<\/h2><p class=\"wp-block-paragraph\">La optimizaci&oacute;n del rendimiento de Node.js no termina despu&eacute;s de una sola ronda de mejoras. Las nuevas funcionalidades, el aumento del tr&aacute;fico, las actualizaciones de las dependencias y el crecimiento de la base de datos pueden generar nuevos problemas de rendimiento con el tiempo.<\/p><p class=\"wp-block-paragraph\">Una vez que hayas solucionado los principales problemas de rendimiento, revisa el resto de la configuraci&oacute;n de producci&oacute;n: gesti&oacute;n de errores, seguridad, gesti&oacute;n de dependencias, configuraci&oacute;n del entorno, registros, pruebas y flujos de trabajo de despliegue.<\/p><p class=\"wp-block-paragraph\">Puede que estos aspectos no siempre afecten directamente a la velocidad, pero desempe&ntilde;an un papel importante en la fiabilidad de la app en producci&oacute;n. Una app r&aacute;pida tambi&eacute;n necesita registros claros, una configuraci&oacute;n segura, dependencias estables y procesos de despliegue predecibles para seguir funcionando correctamente a medida que aumentan el tr&aacute;fico y la complejidad.<\/p><p class=\"wp-block-paragraph\">Seguir las buenas pr&aacute;cticas de desarrollo con Node.js ayuda a que la app siga siendo f&aacute;cil de mantener, segura y preparada para producci&oacute;n a medida que crece. Sigue midiendo, soluciona primero el cuello de botella que m&aacute;s afecte al rendimiento y repite el proceso.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Optimizar el rendimiento de Node.js consiste en identificar y solucionar los aspectos de tu app que la ralentizan para que responda m&aacute;s r&aacute;pido, gestione m&aacute;s tr&aacute;fico, utilice los recursos de forma m&aacute;s eficiente y se mantenga estable bajo carga. Lo mejor es medir primero y solucionar despu&eacute;s los problemas que indiquen los datos. Sin mediciones, [&#8230;]<\/p>\n<p><a class=\"btn btn-secondary understrap-read-more-link\" href=\"\/mx\/tutoriales\/optimizacion-rendimiento-node-js\/\">Read More&#8230;<\/a><\/p>\n","protected":false},"author":190,"featured_media":47859,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"rank_math_title":"Gu\u00eda de optimizaci\u00f3n del rendimiento de Node.js","rank_math_description":"Descubre t\u00e9cnicas de optimizaci\u00f3n del rendimiento de Node.js con an\u00e1lisis de rendimiento, cach\u00e9, clustering, monitorizaci\u00f3n y m\u00e1s.","rank_math_focus_keyword":"optimizaci\u00f3n del rendimiento de Node.js","footnotes":""},"categories":[14502],"tags":[],"class_list":["post-47858","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-app-web"],"hreflangs":[{"locale":"es-ES","link":"https:\/\/www.hostinger.com\/es\/tutoriales\/optimizacion-rendimiento-node-js","default":1},{"locale":"es-AR","link":"https:\/\/www.hostinger.com\/ar\/tutoriales\/optimizacion-rendimiento-node-js","default":0},{"locale":"es-MX","link":"https:\/\/www.hostinger.com\/mx\/tutoriales\/optimizacion-rendimiento-node-js","default":0},{"locale":"es-CO","link":"https:\/\/www.hostinger.com\/co\/tutoriales\/optimizacion-rendimiento-node-js","default":0}],"acf":[],"_links":{"self":[{"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/posts\/47858","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/users\/190"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/comments?post=47858"}],"version-history":[{"count":0,"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/posts\/47858\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/media\/47859"}],"wp:attachment":[{"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/media?parent=47858"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/categories?post=47858"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hostinger.com\/mx\/tutoriales\/wp-json\/wp\/v2\/tags?post=47858"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}