BackVolver al blog

Next.js 14

Next.js 14 incluye mejoras de rendimiento, estabilidad para Server Actions, un nuevo curso sobre el App Router, y más.

Como anunciamos en Next.js Conf, Next.js 14 es nuestra versión más enfocada con:

  • Turbopack: 5,000 pruebas aprobadas para App & Pages Router
    • 53% más rápido en el inicio del servidor local
    • 94% más rápido en actualizaciones de código con Fast Refresh
  • Server Actions (Estable): Mutaciones con mejora progresiva
    • Integrado con caché y revalidación
    • Llamadas simples a funciones o funciona nativamente con formularios
  • Partial Prerendering (Vista previa): Respuesta estática inicial rápida + transmisión de contenido dinámico
  • Next.js Learn (Nuevo): Curso gratuito sobre App Router, autenticación, bases de datos y más.

Actualiza hoy o comienza con:

Terminal
npx create-next-app@latest

Next.js Compiler: Potenciado

Desde Next.js 13, hemos trabajado para mejorar el rendimiento en desarrollo local tanto en Pages como en App Router.

Anteriormente, estábamos reescribiendo next dev y otras partes de Next.js para este esfuerzo. Desde entonces, hemos cambiado nuestro enfoque para ser más incremental. Esto significa que nuestro compilador basado en Rust alcanzará estabilidad pronto, ya que nos hemos enfocado en soportar primero todas las funciones de Next.js.

5,000 pruebas de integración para next dev ahora pasan con Turbopack, nuestro motor subyacente en Rust. Estas pruebas incluyen 7 años de correcciones de errores y reproducciones.

En pruebas en vercel.com, una aplicación grande de Next.js, hemos visto:

  • Hasta 53.3% más rápido en inicio del servidor local
  • Hasta 94.7% más rápido en actualizaciones de código con Fast Refresh

Este benchmark es un resultado práctico de mejoras de rendimiento que puedes esperar con una aplicación grande (y un gran gráfico de módulos). Con 90% de las pruebas para next dev ahora aprobadas, deberías ver un rendimiento más rápido y confiable consistentemente al usar next dev --turbo.

Una vez que alcancemos el 100% de pruebas aprobadas, moveremos Turbopack a estable en una próxima versión menor. También continuaremos soportando webpack para configuraciones personalizadas y plugins del ecosistema.

Puedes seguir el porcentaje de pruebas aprobadas en areweturboyet.com.

Formularios y Mutaciones

Next.js 9 introdujo API Routes — una forma de construir endpoints backend rápidamente junto a tu código frontend.

Por ejemplo, crearías un nuevo archivo en el directorio api/:

pages/api/submit.ts
import type { NextApiRequest, NextApiResponse } from 'next';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const data = req.body;
  const id = await createItem(data);
  res.status(200).json({ id });
}

Luego, en el lado del cliente, podrías usar React y un manejador de eventos como onSubmit para hacer un fetch a tu API Route.

pages/index.tsx
import { FormEvent } from 'react';
 
export default function Page() {
  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
 
    const formData = new FormData(event.currentTarget);
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData,
    });
 
    // Manejar respuesta si es necesario
    const data = await response.json();
    // ...
  }
 
  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

Ahora con Next.js 14, queremos simplificar la experiencia del desarrollador al crear mutaciones de datos. Además, queremos mejorar la experiencia del usuario cuando tiene una conexión lenta o al enviar un formulario desde un dispositivo de baja potencia.

Server Actions (Estable)

¿Qué tal si no necesitas crear manualmente una API Route? En su lugar, podrías definir una función que se ejecute de forma segura en el servidor, llamada directamente desde tus componentes React.

El App Router está construido en el canal canary de React, que es estable para frameworks para adoptar nuevas características. A partir de v14, Next.js se ha actualizado al último canary de React, que incluye Server Actions estables.

El ejemplo anterior de Pages Router puede simplificarse a un archivo:

app/page.tsx
export default function Page() {
  async function create(formData: FormData) {
    'use server';
    const id = await createItem(formData);
  }
 
  return (
    <form action={create}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

Server Actions debería sentirse familiar para desarrolladores que han usado frameworks centrados en servidor antes. Está construido sobre fundamentos web como formularios y la API FormData.

Aunque usar Server Actions a través de un formulario es útil para mejora progresiva, no es un requisito. También puedes llamarlas directamente como función, sin un formulario. Con TypeScript, esto te da seguridad de tipos de extremo a extremo entre cliente y servidor.

Mutaciones de datos, re-renderizado de página o redirección pueden ocurrir en un solo viaje de red, asegurando que los datos correctos se muestren en el cliente, incluso si el proveedor upstream es lento. Además, puedes componer y reutilizar diferentes acciones, incluyendo muchas en la misma ruta.

Caché, Revalidación, Redirección y más

Server Actions están profundamente integradas en todo el modelo App Router. Puedes:

  • Revalidar datos en caché con revalidatePath() o revalidateTag()
  • Redirigir a diferentes rutas con redirect()
  • Establecer y leer cookies con cookies()
  • Manejar actualizaciones optimistas de UI con useOptimistic()
  • Capturar y mostrar errores del servidor con useFormState()
  • Mostrar estados de carga en el cliente con useFormStatus()

Aprende más sobre Formularios y Mutaciones con Server Actions o sobre el modelo de seguridad y mejores prácticas para Server Components y Server Actions.

Partial Prerendering (Vista previa)

Queremos compartir una vista previa de Partial Prerendering — una optimización del compilador para contenido dinámico con una respuesta estática inicial rápida — en la que estamos trabajando para Next.js.

Partial Prerendering se basa en una década de investigación y desarrollo sobre renderizado del lado del servidor (SSR), generación de sitios estáticos (SSG) y revalidación estática incremental (ISR).

Motivación

Hemos escuchado tus comentarios. Actualmente hay demasiados entornos de ejecución, opciones de configuración y métodos de renderizado para considerar. Quieres la velocidad y confiabilidad de lo estático, pero también soporte para respuestas completamente dinámicas y personalizadas.

Tener gran rendimiento global y personalización no debería costar complejidad.

Nuestro desafío fue crear una mejor experiencia para el desarrollador, simplificando el modelo existente sin introducir nuevas APIs para aprender. Aunque el caché parcial de contenido del servidor ha existido, estos enfoques aún no cumplen con los objetivos de experiencia y composabilidad que buscamos.

Partial Prerendering no requiere aprender nuevas APIs.

Basado en React Suspense

Partial Prerendering se define por tus límites de Suspense. Así es como funciona. Considera esta página de ecommerce:

app/page.tsx
export default function Page() {
  return (
    <main>
      <header>
        <h1>Mi Tienda</h1>
        <Suspense fallback={<CartSkeleton />}>
          <ShoppingCart />
        </Suspense>
      </header>
      <Banner />
      <Suspense fallback={<ProductListSkeleton />}>
        <Recommendations />
      </Suspense>
      <NewProducts />
    </main>
  );
}

Con Partial Prerendering habilitado, esta página genera un shell estático basado en tus límites <Suspense />. El fallback de React Suspense se prerenderiza.

Los fallbacks de Suspense en el shell luego se reemplazan con componentes dinámicos, como leer cookies para determinar el carrito, o mostrar un banner basado en el usuario.

Cuando se hace una solicitud, el shell HTML estático se sirve inmediatamente:

<main>
  <header>
    <h1>Mi Tienda</h1>
    <div class="cart-skeleton">
      <!-- Espacio -->
    </div>
  </header>
  <div class="banner" />
  <div class="product-list-skeleton">
    <!-- Espacio -->
  </div>
  <section class="new-products" />
</main>

Como <ShoppingCart /> lee de cookies para ver la sesión del usuario, este componente se transmite como parte de la misma solicitud HTTP que el shell estático. No se necesitan viajes de red adicionales.

app/cart.tsx
import { cookies } from 'next/headers'
 
export default function ShoppingCart() {
  const cookieStore = cookies()
  const session = cookieStore.get('session')
  return ...
}

Para tener el shell estático más granular, esto puede requerir agregar límites de Suspense adicionales. Sin embargo, si ya usas loading.js hoy, este es un límite de Suspense implícito, por lo que no se requerirían cambios para generar el shell estático.

Próximamente

El prerrenderizado parcial está en desarrollo activo. Compartiremos más actualizaciones en una próxima versión menor.

Mejoras en Metadatos

Antes de que el contenido de su página pueda transmitirse desde el servidor, hay metadatos importantes sobre el viewport, esquema de colores y tema que deben enviarse primero al navegador.

Garantizar que estas etiquetas meta se envíen con el contenido inicial de la página ayuda a una experiencia de usuario fluida, evitando que la página parpadee al cambiar el color del tema o que el diseño se altere debido a cambios en el viewport.

En Next.js 14, hemos separado los metadatos bloqueantes y no bloqueantes. Solo un pequeño subconjunto de opciones de metadatos son bloqueantes, y queremos asegurar que los metadatos no bloqueantes no impidan que una página prerrenderizada parcialmente sirva el shell estático.

Las siguientes opciones de metadatos ahora están obsoletas y se eliminarán de metadata en una futura versión principal:

  • viewport: Establece el zoom inicial y otras propiedades del viewport
  • colorScheme: Establece los modos de soporte (claro/oscuro) para el viewport
  • themeColor: Establece el color con el que debe renderizarse el chrome alrededor del viewport

A partir de Next.js 14, hay nuevas opciones viewport y generateViewport para reemplazar estas opciones. Todas las demás opciones de metadata permanecen igual.

Puede comenzar a adoptar estas nuevas APIs hoy. Las opciones existentes de metadata seguirán funcionando.

Curso de Next.js Learn

Hoy lanzamos un nuevo curso gratuito en Next.js Learn. Este curso enseña:

  • El App Router de Next.js
  • Estilos y Tailwind CSS
  • Optimización de fuentes e imágenes
  • Creación de diseños y páginas
  • Navegación entre páginas
  • Configuración de su base de datos Postgres
  • Obtención de datos con Componentes del Servidor (Server Components)
  • Renderizado estático y dinámico
  • Streaming
  • Prerrenderizado parcial (Opcional)
  • Adición de búsqueda y paginación
  • Mutación de datos
  • Manejo de errores
  • Mejora de accesibilidad
  • Adición de autenticación
  • Adición de metadatos

Next.js Learn ha enseñado a millones de desarrolladores los fundamentos del framework, y estamos ansiosos por escuchar sus comentarios sobre esta nueva adición. Diríjase a nextjs.org/learn para tomar el curso.

Otros Cambios

  • [Cambio importante] La versión mínima de Node.js es ahora 18.17
  • [Cambio importante] Eliminación del objetivo WASM para la compilación de next-swc (PR)
  • [Cambio importante] Eliminación del soporte para @next/font en favor de next/font (Codemod)
  • [Cambio importante] Cambio de importación de ImageResponse de next/server a next/og (Codemod)
  • [Cambio importante] El comando next export ha sido eliminado en favor de la configuración output: 'export' (Docs)
  • [Obsoleto] onLoadingComplete para next/image está obsoleto en favor de onLoad
  • [Obsoleto] domains para next/image está obsoleto en favor de remotePatterns
  • [Novedad] Se puede habilitar un registro más detallado sobre el almacenamiento en caché de fetch (Docs)
  • [Mejora] Tamaño de función 80% más pequeño para una aplicación básica de create-next-app
  • [Mejora] Gestión de memoria mejorada al usar el runtime edge en desarrollo

Contribuidores

Next.js es el resultado del trabajo combinado de más de 2,900 desarrolladores individuales, socios de la industria como Google y Meta, y nuestro equipo central en Vercel. Únase a la comunidad en GitHub Discussions, Reddit, y Discord.

Esta versión fue posible gracias a:

Y las contribuciones de: @05lazy, @0xadada, @2-NOW, @aarnadlr, @aaronbrown-vercel, @aaronjy, @abayomi185, @abe1272001, @abhiyandhakal, @abstractvector, @acdlite, @adamjmcgrath, @AdamKatzDev, @adamrhunter, @ademilter, @adictonator, @adilansari, @adtc, @afonsojramos, @agadzik, @agrattan0820, @akd-io, @AkifumiSato, @akshaynox, @alainkaiser, @alantoa, @albertothedev, @AldeonMoriak, @aleksa-codes, @alexanderbluhm, @alexkirsz, @alfred-mountfield, @alpha-xek, @andarist, @Andarist, @andrii-bodnar, @andykenward, @angel1254mc, @anonrig, @anthonyshew, @AntoineBourin, @anujssstw, @apeltop, @aralroca, @aretrace, @artdevgame, @artechventure, @arturbien, @Aryan9592, @AviAvinav, @aziyatali, @BaffinLee, @Banbarashik, @bencmbrook, @benjie, @bennettdams, @bertho-zero, @bigyanse, @Bitbbot, @blue-devil1134, @bot08, @bottxiang, @Bowens20832, @bre30kra69cs, @BrennanColberg, @brkalow, @BrodaNoel, @Brooooooklyn, @brunoeduardodev, @brvnonascimento, @carlos-menezes, @cassidoo, @cattmote, @cesarkohl, @chanceaclark, @charkour, @charlesbdudley, @chibicode, @chrisipanaque, @ChristianIvicevic, @chriswdmr, @chunsch, @ciruz, @cjmling, @clive-h-townsend, @colinhacks, @colinking, @coreyleelarson, @Cow258, @cprussin, @craigwheeler, @cramforce, @cravend, @cristobaldominguez95, @ctjlewis, @cvolant, @cxa, @danger-ahead, @daniel-web-developer, @danmindru, @dante-robinson, @darshanjain-entrepreneur, @darshkpatel, @davecarlson, @David0z, @davidnx, @dciug, @delbaoliveira, @denchance, @DerTimonius, @devagrawal09, @DevEsteves, @devjiwonchoi, @devknoll, @DevLab2425, @devvspaces, @didemkkaslan, @dijonmusters, @dirheimerb, @djreillo, @dlehmhus, @doinki, @dpnolte, @Drblessing, @dtinth, @ducanhgh, @DuCanhGH, @ductnn, @duncanogle, @dunklesToast, @DustinsCode, @dvakatsiienko, @dvoytenko, @dylanjha, @ecklf, @EndangeredMassa, @eps1lon, @ericfennis, @escwxyz, @Ethan-Arrowood, @ethanmick, @ethomson, @fantaasm, @feikerwu, @ferdingler, @FernandVEYRIER, @feugy, @fgiuliani, @fomichroman, @Fonger, @ForsakenHarmony, @franktronics, @FSaldanha, @fsansalvadore, @furkanmavili, @g12i, @gabschne, @gaojude, @gdborton, @gergelyke, @gfgabrielfranca, @gidgudgod, @Gladowar, @Gnadhi, @gnoff, @goguda, @greatSumini, @gruz0, @Guilleo03, @gustavostz, @hanneslund, @HarshaVardhanReddyDuvvuru, @haschikeks, @Heidar-An, @heyitsuzair, @hiddenest, @hiro0218, @hotters, @hsrvms, @hu0p, @hughlilly, @HurSungYun, @hustLer2k, @iamarpitpatidar, @ianldgs, @ianmacartney, @iaurg, @ibash, @ibrahemid, @idoob, @iiegor, @ikryvorotenko, @imranbarbhuiya, @ingovals, @inokawa, @insik-han, @isaackatayev, @ishaqibrahimbot, @ismaelrumzan, @itsmingjie, @ivanhofer, @IvanKiral, @jacobsfletch, @jakemstar, @jamespearson, @JanCizmar, @janicklas-ralph, @jankaifer, @JanKaifer, @jantimon, @jaredpalmer, @javivelasco, @jayair, @jaykch, @Jeffrey-Zutt, @jenewland1999, @jeremydouglas, @JesseKoldewijn, @jessewarren-aa, @jimcresswell, @jiwooIncludeJeong, @jocarrd, @joefreeman, @JohnAdib, @JohnAlbin, @JohnDaly, @johnnyomair, @johnta0, @joliss, @jomeswang, @joostdecock, @Josehower, @josephcsoti, @josh, @joshuabaker, @JoshuaKGoldberg, @joshuaslate, @joulev, @jsteele-stripe, @JTaylor0196, @JuanM04, @jueungrace, @juliusmarminge, @Juneezee, @Just-Moh-it, @juzhiyuan, @jyunhanlin, @kaguya3222, @karlhorky, @kevinmitch14, @keyz, @kijikunnn, @kikobeats, @Kikobeats, @kleintorres, @koba04, @koenpunt, @koltong, @konomae, @kosai106, @krmeda, @kvnang, @kwonoj, @ky1ejs, @kylemcd, @labyrinthitis, @lachlanjc, @lacymorrow, @laityned, @Lantianyou, @leerob, @leodr, @leoortizz, @li-jia-nan, @loettz, @lorenzobloedow, @lubakravche, @lucasassisrosa, @lucasconstantino, @lucgagan, @LukeSchlangen, @LuudJanssen, @lycuid, @M3kH, @m7yue, @manovotny, @maranomynet, @marcus-rise, @MarDi66, @MarkAtOmniux, @martin-wahlberg, @masnormen, @matepapp, @matthew-heath, @mattpr, @maxleiter, @MaxLeiter, @maxproske, @meenie, @meesvandongen, @mhmdrioaf, @michaeloliverx, @mike-plummer, @MiLk, @milovangudelj, @Mingyu-Song, @mirismaili, @mkcy3, @mknichel, @mltsy, @mmaaaaz, @mnajdova, @moetazaneta, @mohanraj-r, @molebox, @morganfeeney, @motopods, @mPaella, @mrkldshv, @mrxbox98, @nabsul, @nathanhammond, @nbouvrette, @nekochantaiwan, @nfinished, @Nick-Mazuk, @nickmccurdy, @niedziolkamichal, @niko20, @nikolovlazar, @nivak-monarch, @nk980113, @nnnnoel, @nocell, @notrab, @nroland013, @nuta, @nutlope, @obusk, @okcoker, @oliviertassinari, @omarhoumz, @opnay, @orionmiz, @ossan-engineer, @patrick91, @pauek, @peraltafederico, @Phiction, @pn-code, @pyjun01, @pythagoras-yamamoto, @qrohlf, @raisedadead, @reconbot, @reshmi-sriram, @reyrodrigez, @ricardofiorani, @rightones, @riqwan, @rishabhpoddar, @rjsdnql123, @rodrigofeijao, @runjuu, @Ryan-Dia, @ryo-manba, @s0h311, @sagarpreet-xflowpay, @sairajchouhan, @samdenty, @samsisle, @sanjaiyan-dev, @saseungmin, @SCG82, @schehata, @Schniz, @sepiropht, @serkanbektas, @sferadev, @ShaunFerris, @shivanshubisht, @shozibabbas, @silvioprog, @simonswiss, @simPod, @sivtu, @SleeplessOne1917, @smaeda-ks, @sonam-serchan, @SonMooSans, @soonoo, @sophiebits, @souporserious, @sp00ls, @sqve, @sreetamdas, @stafyniaksacha, @starunaway, @steebchen, @stefanprobst, @steppefox, @steven-tey, @suhaotian, @sukkaw, @SukkaW, @superbahbi, @SuttonJack, @svarunid, @swaminator, @swarnava, @syedtaqi95, @taep96, @taylorbryant, @teobler, @Terro216, @theevilhead, @thepatrick00, @therealrinku, @thomasballinger, @thorwebdev, @tibi1220, @tim-hanssen, @timeyoutakeit, @tka5, @tknickman, @tomryanx, @trigaten, @tristndev, @tunamagur0, @tvthatsme, @tyhopp, @tyler-lutz, @UnknownMonk, @v1k1, @valentincostam, @valentinh, @valentinpolitov, @vamcs, @vasucp1207, @vicsantizo, @vinaykulk621, @vincenthongzy, @visshaljagtap, @vladikoff, @wherehows, @WhoAmIRUS, @WilderDev, @Willem-Jaap, @williamli, @wiredacorn, @wiscaksono, @wojtekolek, @ws-jm, @wxh06, @wyattfry, @wyattjoh, @xiaolou86, @y-tsubuku, @yagogmaisp, @yangshun, @yasath, @Yash-Singh1, @yigithanyucedag, @ykzts, @Yovach, @yutsuten, @yyuemii, @zek, @zekicaneksi, @zignis, y @zlrlyy