para servicios Node
Qué función, qué consulta, qué despliegue.
Un agente, instalado con un comando, mide cada función asíncrona exportada y cada consulta que hace tu aplicación — y sabe qué función emitió qué consulta. Cada versión se compara con la anterior, así que el hallazgo nombra tu despliegue y no la hora.
Qué mide
- Cada función asíncrona exportada
- Cuánto tardó, y cuánto de eso fue su propio código y no algo que llamó. «¿Se volvió más lento mi código, o lo que llamé?» es aquí un número en vez de una tarde.
- Cada consulta, en cinco clientes
- pg, mysql2, postgres.js, el driver de MongoDB y Prisma — encontrados e instrumentados automáticamente, incluso a través de Mongoose y de un pool de conexiones bajo carga. Filas devueltas, columnas, tamaño de la respuesta y, para MongoDB, el número de idas y vueltas de red que costó realmente una sola lectura.
- Qué función emitió qué consulta
- La parte que hace que el resto merezca leerse. Una consulta se acredita a la función que tiene encima, así que un N+1 aparece en la función que tiene el bucle, no repartido por una consulta que siempre pareció correcta.
- Qué hizo la base de datos para responder
- A Postgres se le pide el plan de cada sentencia — sin enlazar nunca un parámetro, así que no interviene ningún valor tuyo. MySQL se lee en su lugar desde performance_schema: filas examinadas por fila devuelta, y si se usó algún índice. Ambos llegan como el mismo hallazgo: esto lee esa tabla sin índice.
- Tus rutas HTTP, de entrada y de salida
- Peticiones servidas, y tiempo esperando a la API de otro — así que un tercero lento deja de reportarse como que tu código es lento.
Qué encuentra
Cada una de estas se compara con la versión anterior, así que el hallazgo nombra el cambio y no el día.
Un N+1 que no estaba en la versión anterior
Una función que hacía una llamada a la base de datos por petición ahora hace catorce. Anclado al despliegue, así que nombra la versión que lo introdujo.
Una consulta que empezó a leer la tabla entera
Las filas por llamada pasaron de 30 a 30.000. En una base de datos caliente con datos de tamaño staging esto apenas mueve el reloj — y luego tumba producción una semana después.
Una consulta que dejó de usar su índice
El único hallazgo aquí que nombra una causa en vez de un síntoma. A menudo llega antes de que nada vaya lento: la tabla todavía es lo bastante pequeña como para que un escaneo esté bien, y se convierte en una caída semanas después, cuando ya no lo es.
Tu propio código volviéndose más lento
Tiempo dentro de la función y no en lo que llamó — separado, para que mires en el archivo correcto al primer intento.
Una lectura que se convirtió en cientos de esperas de red
MongoDB responde un cursor por lotes. Cuando un resultado supera un lote, una lectura se convierte en decenas o cientos de idas y vueltas secuenciales — los documentos son idénticos, así que nada más en el sistema se mueve salvo el reloj.
Algo que ahora se llama dentro de un bucle
Sin cambios por llamada — misma velocidad, mismos datos — pero llamado cientos de veces donde antes se llamaba una.
Una consulta que calladamente no devuelve nada
Funcionó, sin error, sin llamada lenta, y volvió vacía donde antes volvía con filas. La forma más común en que se rompe uno de estos servicios hace los números más pequeños, no más grandes.
Qué aparece en tu lista
No es un panel que leer. Una tarjeta por hallazgo, con las cifras, la versión que las cambió y las pruebas que tu agente de código necesita para escribir el arreglo.
Estos son los números que imprime `pnpm e2e`, en el clon de este repositorio de cualquiera. Prepara un servicio, publica una versión con dos regresiones reales y las detecta — así que aquí no hay ningún número elegido por nosotros.
orders.getUserOrdersUna cláusula WHERE desapareció en una refactorización, así que la función se trae la tabla entera y la filtra en JavaScript. En una base de datos caliente esto apenas movió el reloj.
desde la versión v2, frente a la v1
orders.enrichOrdersUna consulta se movió dentro de un bucle. Todas ellas son rápidas, así que ninguna petición individual parece mal — el número es lo único que cambió.
desde la versión v2, frente a la v1
Cómo se instala
Dáselo al agente de código que ya tienes abierto. Lee el repositorio, deduce si eso significa una configuración de Next, un plugin de Vite o un comando de arranque, y lo conecta — y luego arregla lo que se encuentre, en la misma conversación.
claude mcp add sixty \
-e SIXTY_API_KEY=sixty_sk_… \
-e SIXTY_ENDPOINT=https://ingest.sixty.sh \
-- npx -y @sixty-sh/mcp
# or by hand, in your server entry:
import { init } from '@sixty-sh/node'
init()El identificador de versión se recoge por su cuenta de Vercel, Render, Railway, Fly, Heroku o GitHub Actions. La primera comparación llega tras tu siguiente despliegue, porque no hay nada con lo que comparar una sola versión.
Qué no hace
- MySQL y MongoDB no reportan árbol de plan. El EXPLAIN de MySQL necesita valores de parámetros reales y el explain de MongoDB necesita un filtro real, y este agente descarta los valores en cuanto los ve — así que para MySQL la conclusión se lee de performance_schema, y para MongoDB todavía no hay nada.
- Los generadores asíncronos los salta la transformación de compilación. Envolver uno mediría cuánto tardó quien lo llamó en obtener un iterador, que no es el número que quiere nadie.
- El agente mide lo que puede alcanzar desde JavaScript. El tiempo dentro de un módulo nativo, o en otro proceso, es tiempo que solo puede ver como espera.
Si estás aquí por una de estas
Descubre qué hizo tu último cambio.
¡Pruébalo!¿Construyes otra cosa? Mira servicios Python, aplicaciones Lovable o aplicaciones React Native — esas páginas son distintas, y también lo es lo que podemos ver.