
En resumen
SvelteKit 3 es sobre todo pulido, pero cuatro cambios no son cosméticos: la config pasa a vite.config.ts, $lib se convierte en #lib, tsconfig extiende $app/tsconfig y las variables de entorno se mueven a src/env.ts.
SvelteKit 3 salió el 1 de octubre de 2026, y sus notas son inusualmente sinceras: es el mismo framework con más pulido, más seguridad de tipos y menos trastos. Eso es buena noticia para una actualización, porque el trabajo es en su mayoría mecánico; pero unos pocos cambios tocan suficientes archivos como para que la migración oficial sea el único punto de partida sensato.
Esta guía ejecuta la migración y luego recorre los cuatro cambios que no puede terminar por ti.
01Qué cambió realmente
Los cambios rompientes son pocos y de amplio alcance:
| Área | SvelteKit 2 | SvelteKit 3 |
|---|---|---|
| Config del framework | svelte.config.js | vite.config.ts |
| Alias de código compartido | $lib | subpath imports #lib |
| Config de TypeScript | extiende ./.svelte-kit/tsconfig.json | extiende $app/tsconfig |
| Variables de entorno | implícitas | declaradas en src/env.ts |
| APIs de service worker | $service-worker | $app/env, $app/paths, $app/manifest |
| Enrutado superficial | pushState / replaceState | goto(..., { shallow: true }) |
| Vite | 7 soportado | 8 obligatorio (Rolldown) |
Otros dos cambios importan en producción: el manejo de errores ahora cubre errores de render además de los de load, y todos los errores —incluidos los que lanzas tú con error(...)— pasan por tu lógica de handleError. Las trazas de pila también llevan sourcemap ahora.
Requiere Svelte 5 y Vite 8
SvelteKit 3 se apoya en los error boundaries de Svelte 5 y requiere Vite 8. Si sigues en Svelte 4, sube primero a Svelte 5 y mantén las dos migraciones separadas.
02Ejecuta primero la migración oficial
El CLI sv incluye una migración que reescribe lo que puede y deja una lista de TODO para el resto. Ejecútala en una rama limpia, sin trabajo sin confirmar.
git checkout -b chore/sveltekit-3
npx sv migrate sveltekit-3 --tasks all --confirm
--tasks all ejecuta cada tarea de migración en orden, y --confirm omite el prompt interactivo para que la ejecución sea reproducible. Revisa la lista de TODO antes de editar nada a mano: te dice exactamente qué imports y bloques de config no pudo reescribir.
Después actualiza dependencias y deja que el toolchain saque a la luz lo que queda:
npm install
npx svelte-kit sync
npm run check
svelte-kit sync regenera los tipos de los que dependen el tsconfig y el cambio a #lib. Si lo omites, el editor reportará imports rotos que la build resolvería sin problema.
03Mueve la configuración a vite.config.ts
El plugin de SvelteKit recibe ahora su configuración donde Vite la necesita, en lugar de a través de una resolución asíncrona de svelte.config.js. En la práctica, importas el plugin en vite.config.ts y le pasas el objeto que antes era la config.
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
sveltekit({
// El objeto `kit` que antes vivía en svelte.config.js.
adapter: undefined,
alias: {}
})
]
})
La forma exacta del objeto está documentada en la guía de migración de SvelteKit 3, porque depende del adapter y las opciones de preprocesador que usara tu app. Trata el bloque anterior como el destino, no como una respuesta para copiar y pegar: mueve tus ajustes de kit, borra svelte.config.js y confirma que el adapter resuelve en una build real, no solo en dev.
04Sustituye $lib por #lib
El código compartido sigue en src/lib; solo cambia la ruta de import. Los subpath imports son una función de Node que Vite y TypeScript entienden de forma nativa, y por eso SvelteKit pudo borrar el código que antes sincronizaba ambos.
// SvelteKit 2
import { formatPrice } from '$lib/format'
import { Button } from '$lib/components'
// SvelteKit 3
import { formatPrice } from '#lib/format.ts'
import { Button } from '#lib/components/index.ts'
La trampa es la resolución. Los subpath imports deben ser inequívocos, así que #lib/format a secas falla y necesitas #lib/format.ts o #lib/format/index.ts. La tarea de migración reescribe casi todos los imports; cuando termine, busca cualquier $lib restante.
grep -rn "\$lib" src/ --include='*.ts' --include='*.svelte' | head -30
Un subpath import ambiguo falla al comprobar tipos
Si
npm run checkdice que no encuentra#lib/foo, la solución casi siempre es una extensión explícita o unindex.ts. Es una regla de resolución, no un bug de SvelteKit.
05Simplifica el tsconfig y declara las variables de entorno
Tu tsconfig.json ya no extiende un archivo generado dentro de .svelte-kit. Extiende $app/tsconfig, que trae más opciones de compilador recomendadas, así que la mayoría de apps pueden borrar su propio bloque compilerOptions. Debes fijar include y exclude explícitamente, y añadir el service worker a exclude.
Las variables de entorno cambian más. En lugar de recurrir a $env/static/private y compañía según haga falta, declaras en src/env.ts las variables de las que depende tu app, marcando cada una como pública o privada y como resuelta en build o al arrancar. Las librerías de Standard Schema pueden validarlas.
// src/env.ts — forma ilustrativa; consulta la guía de migración para la API exacta.
import { defineEnv } from '$app/env'
export const env = defineEnv({
DATABASE_URL: { private: true },
PUBLIC_API_BASE: { public: true, buildTime: true }
})
La recompensa son variables con tipos, validadas e importadas donde se usan, en vez de sacadas de un módulo cajón de sastre. El coste es que cada referencia implícita a process.env necesita una declaración, y una que falte falla en build en lugar de en runtime, que es justo la idea.
06Service workers, errores y enrutado superficial
Tres cambios menores que conviene revisar a mano:
- Los service workers dejan de importar de
$service-workery toman lo que necesitan de$app/env,$app/pathsy el nuevo$app/manifest. Si quieres tipos precisos, añade untsconfig.jsonjunto al service worker que extienda$app/tsconfig/service-worker. - El manejo de errores ahora cubre errores de render, y todos los errores pasan por
handleError. Audita esa función: la lógica de logging que asumía que solo llegaban errores de load puede ver de repente mucho más tráfico. - El enrutado superficial usa
goto(url, { shallow: true })en vez depushState/replaceState. Las navegaciones superficiales ahora disparanbeforeNavigate, ypersistState: trueconserva el estado de la página tras una recarga.
07Verifica la actualización antes de fusionar
- Ejecuta
npm run checky elimina cada error de tipos; no fusiones rodeándolos. - Ejecuta la build de producción, no solo dev, para que se recorran el adapter y la ruta de Vite 8.
- Prueba de punta a punta un flujo completo de usuario, incluida una form action y una ruta que falle.
- Revisa el reporte de errores: provoca un error de render y confirma que llega a
handleErrorcon traza mapeada. - Compara
vite.config.tscon el antiguosvelte.config.jspara asegurarte de que ninguna opción dekitse perdió en el traslado.
Haz que la migración sea su propio commit
La migración de
svtoca muchos archivos. Confírmala sola y revísala con una herramienta de diff antes de añadir tus propios arreglos. Mezclar un renombrado mecánico de 200 archivos con trabajo de features hace casi imposible bisecar una regresión.
08Errores comunes y soluciones
| Error | Causa | Solución |
|---|---|---|
No encuentra el módulo #lib/foo | Subpath import ambiguo | Usa #lib/foo.ts o #lib/foo/index.ts |
| Una opción de config no surte efecto | Sigue en un svelte.config.js residual | Muévela al plugin sveltekit() |
| Errores de tipos en un checkout limpio | Los tipos generados están obsoletos | Ejecuta npx svelte-kit sync |
| Falta una variable de entorno en build | Sin declarar en src/env.ts | Declárala, pública o privada |
| Fallan los tipos del service worker | Import antiguo de $service-worker | Importa de los módulos $app/* |
La actualización es una tarde de trabajo en una app pequeña y una semana cuidadosa en una grande, pero la forma es predecible: deja que sv haga los renombrados y dedica tu atención al traslado de config, las declaraciones de entorno y la ruta de errores. Esos son los tres sitios donde una build en verde todavía puede esconder una app rota.
Compara svelte.config.js y vite.config.ts antes y después de la migración automática.
Comparador de diferenciasPreguntas frecuentes
¿SvelteKit 3 es una reescritura?
No. El equipo lo describe como el mismo framework con más pulido, más seguridad de tipos y menos código heredado. Casi todos los cambios son mecánicos y la migración oficial cubre la mayoría.
¿Cuál es el mayor cambio rompiente?
La configuración sale de svelte.config.js y entra en vite.config.ts. El resto es menor, pero el renombrado a #lib y el cambio de tsconfig tocan casi todos los archivos de una app grande.
¿Hay que usar extensiones de archivo explícitas con #lib?
Sí, para la resolución. Como son subpath imports de Node, TypeScript y Node exigen rutas inequívocas, así que `#lib/foo` pasa a `#lib/foo.ts` o `#lib/foo/index.ts`.
¿Están estables las remote functions en SvelteKit 3?
Todavía no. Las remote functions siguen necesitando un flag experimental, y el equipo dice que terminarlas es la prioridad tras el lanzamiento.
¿Puedo actualizar directamente una app de Svelte 4?
SvelteKit 3 requiere Svelte 5, así que el orden práctico es pasar primero a Svelte 5 y luego ejecutar la migración de SvelteKit. Hacer las dos cosas a la vez hace mucho más difícil aislar un fallo.
Artículos relacionados
- Compara dos textos con un comparador de diferencias
Revisa el diff de la migración antes de confirmarlo.
- Cómo formatear, validar y minificar JSON
package.json y tsconfig son JSON: valida los que edites.
Herramientas relacionadas
- Comparador de diferencias
Detecta cada línea de config que tocó la migración.
- Validador JSON
Detecta un tsconfig o package.json roto.
- Formateador JSON
Lee un diff ruidoso de package.json.