tsconfig paths en Next.js 16 App Router: cuándo ayudan y cuándo rompen el build sin aviso
Agregar un path alias en el tsconfig.json tiene la misma energía que pegar un acceso directo en el escritorio: parece una mejora de calidad de vida hasta que un día el acceso directo apunta a nada y no hay ningún cartel que te diga por qué.
Con tsconfig paths en Next.js 16 App Router, la trampa es exactamente esa. tsc lo acepta, el editor no se queja, el dev server levanta sin errores — y después el build de producción explota silenciosamente, o peor: termina pero con módulos que no se resolvieron como esperabas. Y el log no dice "el problema es el alias", dice algo críptico sobre un módulo que no existe o una importación circular que apareció de la nada.
Mi tesis antes de arrancar: los tsconfig paths no son una herramienta universal. Son una herramienta de mapeo de tipos y de editor que puede integrarse con el bundler, pero solo si entendés qué resuelve cada pieza en el pipeline. El criterio no es "usalos o no" — es "entendé quién resuelve qué antes de agregar un alias".
Por qué tsconfig paths y Next.js 16 no son tan directos como parecen
Antes de hablar de roturas, vale la pena entender qué hace exactamente paths en el tsconfig.json.
Según la documentación oficial de TypeScript, paths es una instrucción para el type checker — no para el runtime, no para el bundler. TypeScript usa este mapeo para saber cómo resolver tipos cuando encontrás un import como @/components/Button. Lo que hacés con esa información después — ejecutarla en Node, bundlearla con webpack o Turbopack, correrla en un worker — es responsabilidad de otra herramienta.
Next.js, por su parte, documenta el soporte de path aliases y lo integra en su pipeline de build. El App Router con webpack o Turbopack lee el tsconfig.json y traduce esos aliases al resolver de módulos del bundler. Eso funciona — con condiciones.
El problema aparece cuando esas condiciones no se cumplen. En un monorepo con pnpm workspaces, esas condiciones son más frágiles de lo que sugiere la documentación.
Los 3 casos de rotura que aparecen seguido
Estos son los patrones de falla más documentados y reproducibles al trabajar con tsconfig paths en Next.js 16 App Router dentro de un monorepo. No son hipótesis — son escenarios que podés reproducir:
Caso 1: tsc pasa, el bundler no encuentra el módulo
El escenario: configurás un alias @ui/* que apunta a un paquete interno del workspace. El type checker no se queja. El dev server tampoco. Corrés next build y aparece:
Module not found: Can't resolve '@ui/button'
¿Por qué? Porque en un workspace con pnpm, el resolver de Next.js (webpack o Turbopack) necesita que el paquete esté correctamente linkeado en node_modules y que el alias en el tsconfig.json sea coherente con ese path físico. Si el paths apunta a ../../packages/ui/src pero el bundler espera resolver desde node_modules/@ui/button, hay una divergencia silenciosa.
La configuración que causa el problema:
// tsconfig.json — versión problemática
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
// Esto TypeScript lo acepta, pero el bundler no ve lo mismo
"@ui/*": ["../../packages/ui/src/*"]
}
}
}La corrección: dejar que el package manager resuelva el paquete como dependencia declarada, y usar el alias solo para la ruta interna de la app:
// tsconfig.json — versión que sobrevive al build
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
// Alias local para la app, no para paquetes del workspace
"@/*": ["./src/*"]
}
}
}Para paquetes del workspace, la dependencia en package.json + el link de pnpm es suficiente. No hace falta un alias adicional.
Caso 2: Server Components no propagan los paths correctamente
Este es el más sutil. En el App Router, los Server Components se ejecutan en un contexto de Node.js diferente al del cliente. Si un alias del tsconfig.json resuelve bien en el cliente pero el módulo apuntado importa algo que no es compatible con el entorno de servidor (por ejemplo, usa APIs del browser o tiene side effects que asumen window), el build puede fallar en la fase de servidor con un error de importación que parece de resolución pero en realidad es de compatibilidad.
El síntoma típico:
Error: Cannot find module '@/lib/analytics'
at Function.Module._resolveFilename
Donde @/lib/analytics existe y TypeScript no se queja. El problema real es que el módulo importa algo incompatible con el runtime de servidor, y Next.js no siempre da el stacktrace completo.
La forma de diagnosticarlo: agregá "use client" temporalmente al componente que falla. Si el error desaparece, el problema no es el alias — es la compatibilidad del módulo con el runtime de servidor.
// diagnostico-server-component.tsx
// Paso 1: agregá esta directiva para aislar el origen del error
"use client"
// Si el build pasa con esta directiva y falla sin ella,
// el alias resuelve bien — el problema es el módulo apuntado
import { analytics } from "@/lib/analytics"Caso 3: baseUrl mal configurado rompe la resolución absoluta
Este aparece cuando configurás paths sin un baseUrl coherente. La documentación de TypeScript es clara: paths se resuelve relativo a baseUrl. Si baseUrl no está definido o apunta a un directorio incorrecto, los aliases son basura silenciosa.
El patrón problemático en monorepos: copiar un tsconfig.json de un proyecto single-repo donde baseUrl es "." (raíz del proyecto) y usarlo en un paquete que tiene su propia raíz. El "." ahora apunta a otro directorio.
// tsconfig.json de un paquete interno — problema
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
// baseUrl no se sobreescribe, hereda "." del base
// que en el contexto del base apuntaba a la raíz del monorepo
// acá apunta al paquete — los aliases del base ya no sirven
"paths": {
"@/*": ["./src/*"] // Esto puede estar correcto o no dependiendo del contexto
}
}
}La regla simple: siempre declarar baseUrl explícitamente en cada tsconfig.json que usa paths. No confiar en la herencia para este campo.
Qué dice la documentación oficial y qué no dice
La documentación de Next.js sobre path aliases muestra el caso feliz: un proyecto single-repo con @/* apuntando a ./src/*. Funciona perfecto en ese escenario.
Lo que la documentación no cubre explícitamente:
- Cómo interactúa el resolver de Next.js con aliases que apuntan fuera del directorio de la app (hacia paquetes del workspace)
- Qué pasa cuando Turbopack y webpack resuelven diferente un mismo alias (esto cambia entre versiones)
- Cómo depurar cuando el error de build no menciona el alias sino el módulo resultante
La documentación de TypeScript sobre paths es precisa pero no menciona bundlers. Es una spec de type checker, no de runtime. Leerla con esa lente cambia cómo interpretás los errores.
Lo incómodo: hay una brecha de documentación entre "TypeScript acepta el alias" y "el build de producción también lo acepta". Esa brecha es donde viven los tres casos anteriores.
Checklist de decisión: cuándo configurar paths y cuándo no
Antes de agregar un alias nuevo, pasalo por este filtro:
Usá tsconfig paths si:
- El alias apunta a un directorio dentro de la misma app (ej:
./src/components) - El
baseUrlestá declarado explícitamente en el mismo archivo - Podés verificar que
next buildpasa sin el dev server corriendo
Evitá tsconfig paths si:
- El alias apunta a un paquete del workspace — dejá que pnpm/npm lo resuelva como dependencia
- Estás heredando
tsconfig.jsonsin revisar elbaseUrlque hereda - El módulo apuntado mezcla imports del browser y del servidor
Mirá esto antes de agregar un alias:
# Verificá que el build pasa en frío, sin caché
rm -rf .next
pnpm build
# Si usás Turbopack en dev, verificá también con webpack en build
# porque pueden resolver diferente en versiones tempranas de Next.js 16Señal de alerta: si el error de build menciona un módulo que sí existe físicamente pero dice que no lo encuentra, el alias está involucrado. La pista está en el path del módulo que aparece en el error — si es diferente al path físico real, hay una divergencia de resolución.
Para proyectos donde TypeScript strict mode está activo (que debería ser la norma en 2026), los aliases mal configurados combinados con noUncheckedIndexedAccess o moduleResolution: bundler pueden producir errores de tipos que parecen de lógica de negocio pero en realidad son de resolución de módulos.
Lo que no podés concluir sin experimento propio
Antes de cerrar, límites claros:
- No puedo afirmar que estos casos se reproducen en toda configuración de Next.js 16. El comportamiento puede variar según la versión exacta de Next.js, si usás Turbopack o webpack, y la versión de TypeScript.
- No podés asumir que si el dev server no falla, el build de producción tampoco. Son pipelines diferentes.
- No está documentado oficialmente cómo Turbopack resuelve aliases que apuntan fuera del directorio de la app en un monorepo. Si trabajás con Turbopack en desarrollo y webpack en producción (que era el default en Next.js 14-15), los resultados pueden divergir.
Para validar en el propio entorno: el experimento reproducible es el rm -rf .next && pnpm build sin dev server. Si pasa ahí, el alias es estable.
FAQ: preguntas frecuentes sobre tsconfig paths en Next.js
¿Next.js 16 lee automáticamente los paths del tsconfig.json?
Sí, Next.js lee el tsconfig.json y configura el resolver de webpack (o Turbopack) con esos aliases. Pero "leer" no significa "resolver de forma idéntica a TypeScript". El type checker y el bundler son herramientas distintas; Next.js hace el puente, pero con limitaciones en escenarios de monorepo.
¿Hay diferencia entre baseUrl solo y baseUrl + paths?
Sí, y es importante. Solo con baseUrl, podés importar desde components/Button sin el ./ relativo. Agregando paths, creás un alias con nombre como @/components/Button. El segundo requiere el primero para funcionar correctamente — paths es relativo a baseUrl.
¿Por qué el dev server no falla pero next build sí?
Porque el dev server usa un compilador incremental que tolera más ambigüedad. El build de producción hace un análisis completo del grafo de módulos y es más estricto con la resolución. Un alias que el dev server "adivina" puede romper en build.
¿Turbopack resuelve los paths igual que webpack?
No necesariamente, especialmente en versiones tempranas de Next.js 16 y para paths que apuntan fuera del directorio de la app. Si usás --turbopack en dev, verificá siempre el build de producción (que por defecto usa webpack) por separado.
¿Cómo sé si un alias está causando el error de build o es otra cosa? Temporalmente reemplazá el alias por el path relativo en el archivo que falla. Si el error desaparece, el alias es el problema. Si sigue igual, la causa está en el módulo apuntado, no en el mapeo.
¿En un monorepo con pnpm, conviene usar paths para los paquetes del workspace?
No es lo más robusto. El patrón más estable es declarar el paquete como dependencia en package.json (ej: "@repo/ui": "workspace:*") y dejar que pnpm lo linkee en node_modules. Reservar paths para aliases internos de la app simplifica el debugging cuando algo falla.
Mi postura y el próximo paso concreto
Los tsconfig paths en Next.js 16 App Router son útiles cuando se usan para lo que fueron diseñados: alias internos dentro de la app, con baseUrl explícito y verificación de build en frío. Cuando se estiran para resolver paquetes del workspace o se heredan sin revisar el contexto, se convierten en una fuente de errores que el tooling no siempre comunica bien.
No compro la recomendación de "usá siempre @/" sin más contexto. Tampoco compro el extremo opuesto de evitar aliases completamente. El trade-off honesto es este: los aliases mejoran la legibilidad del código, pero agregan una capa de indirección que puede divergir entre herramientas. En un monorepo con múltiples tsconfig.json, esa divergencia es más probable.
El próximo paso si estás trabajando con esto: abrí el tsconfig.json de cada paquete del workspace, verificá que baseUrl esté declarado explícitamente, y corrí next build en frío una vez. Si el build pasa, los aliases son estables. Si no pasa, tenés los tres casos anteriores como guía de diagnóstico.
Si el tema de configuración de TypeScript en producción te interesa en más profundidad, tengo un análisis más detallado sobre las opciones de tsconfig que más impactan en producción. Y si trabajás con arquitecturas que cruzan múltiples servicios — donde los paths entre módulos se vuelven una decisión de diseño, no solo de configuración — el contexto de arquitectura backend con JWT y OAuth puede sumar.
Fuentes originales:
- TypeScript Docs — Path Mapping: https://www.typescriptlang.org/tsconfig#paths
- Next.js Docs — Absolute Imports and Module Path Aliases: https://nextjs.org/docs/app/getting-started/installation#set-up-absolute-imports-and-module-aliases
Artículos Relacionados
¿De verdad necesitás fp-ts, o te alcanza un union nativo?
Escribí sobre fp-ts esta semana y me quedó la duda incómoda: ¿hacía falta toda esa maquinaria? Análisis de cuándo un discriminated union nativo resuelve lo mismo que Either/Option sin la curva.
14 ago 2026 · 7′ · Tutoriales · TypeScript · arquitectura de software
Functional programming con TypeScript: lo que fp-ts enseña aunque no lo uses en producción
fp-ts es una universidad, no un framework de producción para la mayoría. Pero ignorarlo completamente es dejar conceptos valiosos sobre la mesa. Recorrido honesto por Option, Either y pipe desde TypeScript estricto del día a día, con la postura de por qué la librería no es el punto.
07 ago 2026 · 10′ · Tutoriales · Next.js · TypeScript
Qwen3 en local con Ollama: qué cambió en la arquitectura y si vale el cambio
Qwen3 llegó con thinking mode y mejoras reales en código. Pero antes de reemplazar el modelo que ya tenés corriendo en Ollama, hay preguntas técnicas que responder primero. Acá las respondo sin vender hype.
02 ago 2026 · 9′ · Tutoriales · TypeScript · Inferencia Local
Comentarios (0)
¿Qué pensás de esto?
Dejá tu comentario en 10 segundos.
Usamos tu login solo para mostrar tu nombre y avatar. Nada de spam.
Todavía nadie comentó. Sé el primero — tu opinión vale oro cuando somos pocos.