Sebastian Gomez
Obteniendo Datos con Next.js
Hay muchas maneras de traer datos a nuestra aplicación con Next.js. Dependiendo de cuándo y cómo necesites la información, habrá varias alternativas que te pueden funcionar.
Antes de empezar: Pages Router y App Router. Este post explica el modelo de datos del Pages Router (getStaticProps, getStaticPaths, getServerSideProps). Sigue siendo válido si tu proyecto usa la carpeta pages/, pero desde Next.js 13 el App Router (la carpeta app/) es el paradigma recomendado y esas funciones no existen allí. Más abajo encontrarás una sección con el equivalente en App Router. Si empiezas un proyecto nuevo en Next.js 16, salta directo a esa sección.
Empecemos por lo que ya sabes. Si quieres traer datos del lado del cliente lo debes seguir haciendo como lo haces normalmente: usando axios, fetch, SWR o TanStack Query (antes react-query, hoy @tanstack/react-query) dentro de un useEffect o del hook que estés usando. Las clases con componentDidMount quedaron atrás; en React 19 el patrón natural son los hooks o, mejor aún, los Server Components.
Tip: Next.js inyecta automáticamente fetch para que lo puedas usar en tu aplicación.
Ahora, si tu objetivo es obtener datos desde el lado del servidor o "antes de tiempo" (ahead of time), en el Pages Router tenemos tres opciones:
getStaticPropsgetStaticPathsgetServerSideProps
Datos estáticos (Static Data)
Todos los métodos anteriores son para el prerenderizado de páginas solamente. No puedes usarlos en componentes ni para traer datos del lado del cliente.
Hablemos entonces sobre getStaticProps en una página:
// Creamos un archivo llamado 'index.js' dentro de la carpeta 'pages'
// Este archivo define un componente de funcion llamado 'IndexPage'
const IndexPage = () => {
// Aqui se escribe JSX que define el contenido del componente 'IndexPage'
}
// Exportamos el componente 'IndexPage' como el valor predeterminado de este archivo
export default IndexPage
// Creamos una funcion asincrona llamada 'getStaticProps' que se usa
// en la generacion estatica de paginas en Next.js
export async function getStaticProps(context) {
// Aqui definimos las propiedades que se pasaran al componente 'IndexPage'
return {
props: {}
}
}Por tener escrita esta función en el archivo de tu página y exportándola por defecto, Next.js va a ejecutar esta función en tiempo de construcción, y cualquier resultado será pasado como una propiedad en la página exportada.
Tip: Los resultados de esta función se guardan dentro de un archivo JSON y se pasan como propiedad al componente de la página del lado del cliente en tiempo de ejecución.
Esta función, al igual que las otras, solo se ejecuta del lado del servidor. De hecho, ni siquiera el código de esta función se envía al cliente; por tanto, se pueden hacer cosas muy interesantes aquí:
- Interactuar con el sistema de archivos.
- Conectarse a una base de datos.
- Trabajo costoso del lado del backend.
El objeto de contexto tiene los parámetros cuando un usuario consulta una de nuestras páginas y esa página es dinámica, es decir, tiene [id].js o [parametro].js o lo que sea dentro de [ ]. Por esto, el objeto contexto expone esos parámetros en context.params. Pero imagina que tienes una lista de posts y no sabes cuántos ni cuáles son, y aun así quieres hacer que tu sitio sea estático. Allí entra a jugar el método getStaticPaths. Veamos un ejemplo:
// Creamos un archivo llamado '[slug].js' dentro de la carpeta 'blog', en la carpeta 'pages'
// Este archivo define un componente de funcion llamado 'IndexPage'
const IndexPage = () => {
// Aqui se escribe JSX que define el contenido del componente 'IndexPage'
}
// Exportamos el componente 'IndexPage' como el valor predeterminado de este archivo
export default IndexPage
// 'getStaticPaths' indica a Next.js que rutas dinamicas debe generar estaticamente.
// Devuelve un objeto con 'paths' (las rutas) y 'fallback' (obligatorio).
export async function getStaticPaths() {
// Importante: en build time NO hay un origen, asi que un fetch relativo como
// '/api/posts' falla. Usa una URL absoluta o lee los datos directamente
// (sistema de archivos o base de datos).
const results = await fetch('https://www.tu-sitio.com/api/posts')
const posts = await results.json()
const paths = posts.map(post => ({ params: { slug: post.slug } }))
// 'paths' debe tener la forma [{ params: { slug: 'post-slug' } }]
// 'fallback' es obligatorio: false, true o 'blocking'
return { paths, fallback: false }
}
// 'getStaticProps' obtiene los datos de cada pagina en tiempo de compilacion
export async function getStaticProps({ params }) {
// De nuevo, URL absoluta o acceso directo a los datos en el servidor
const res = await fetch(`https://www.tu-sitio.com/api/post/${params.slug}`)
const post = await res.json()
return {
props: { post }
}
}Rutas estáticas (Static Paths)
Si una página tiene una ruta dinámica [id].js y usa getStaticProps, también deberá usar getStaticPaths para poder prerenderizar todas las páginas en tiempo de compilación en el HTML.
Tip: getStaticPaths siempre debe devolver una clave fallback. Usa fallback: 'blocking' (o true) si tienes un sitio web muy grande y no quieres prerenderizar estáticamente toooodas las páginas de una sola vez; en ese caso, las rutas que no generaste en build se renderizan bajo demanda. Si no, usa fallback: false y cualquier ruta no listada devolverá un 404.
Datos desde el servidor (Server Data)
Finalmente, tenemos getServerSideProps. Este método se ejecuta cada vez que se entra a la página donde lo has escrito, así que, a diferencia de getStaticProps, vas a esperar por todos los datos del API en cada request, incluyendo parámetros, headers y los objetos request y response. Veamos un ejemplo:
// Creamos un componente de funcion llamado 'IndexPage'
const IndexPage = () => {
// Aqui se escribe JSX que define el contenido del componente 'IndexPage'
}
// Exportamos el componente 'IndexPage' como el valor predeterminado de este archivo
export default IndexPage
// 'getServerSideProps' se ejecuta en cada request, del lado del servidor
export async function getServerSideProps() {
// Aqui obtenemos los datos de una fuente externa y los convertimos en JSON
const response = await fetch(`https://somedata.com`)
const data = await response.json()
// Devolvemos un objeto con 'props' que contiene los datos para 'IndexPage'
return { props: { data } }
}Y en el App Router (Next.js 13 a 16)
Si tu proyecto usa la carpeta app/, el paradigma por defecto desde Next.js 13 y el recomendado en Next.js 16, las tres funciones anteriores ya no aplican. En su lugar, los componentes de la carpeta app/ son Server Components y pueden ser async, así que puedes hacer fetch directamente dentro del componente. El cacheo se controla con las opciones de fetch.
El mapeo mental es sencillo:
getStaticProps(datos estáticos en build) se reemplaza por un Server Componentasyncconfetch(..., { cache: 'force-cache' }).getServerSideProps(datos en cada request) se reemplaza por un Server Componentasyncconfetch(..., { cache: 'no-store' }).- La revalidación incremental (ISR) se logra con
fetch(..., { next: { revalidate: 60 } }). getStaticPaths(qué rutas dinámicas generar) se reemplaza por la funcióngenerateStaticParams.
// app/blog/[slug]/page.js (App Router)
// Reemplaza a getStaticPaths: define que slugs se generan estaticamente
export async function generateStaticParams() {
const posts = await fetch('https://www.tu-sitio.com/api/posts').then(r => r.json())
return posts.map(post => ({ slug: post.slug }))
}
// El componente es un Server Component async: el fetch ocurre en el servidor.
// 'force-cache' lo hace estatico (como getStaticProps); 'no-store' lo hace
// dinamico por request (como getServerSideProps).
export default async function PostPage({ params }) {
const { slug } = await params
const post = await fetch(`https://www.tu-sitio.com/api/post/${slug}`, {
cache: 'force-cache',
}).then(r => r.json())
return <article>{post.title}</article>
}Nota: Las opciones de caché de fetch y el comportamiento por defecto del App Router han cambiado entre versiones de Next.js. En particular, fetch dejó de cachear por defecto a partir de Next.js 15 (el valor por defecto es "auto no cache"); usa cache: "force-cache" para cachear y next: { revalidate: n } para ISR. Además, en Next.js 15 y posteriores params es una promesa y debe usarse con await.
Entonces, ¿cuándo usar cuál?
- ¿Necesitas usar datos en tiempo de ejecución y NO necesitas Server Side Rendering? R/: Usa
fetchoaxiosdesde el lado del cliente dentro de unuseEffecto del hook adecuado (SWR o TanStack Query). - ¿Necesitas datos en tiempo de ejecución que varían de request a request y SÍ necesitas Server Side Rendering? R/: Usa
getServerSideProps(Pages Router) o un Server Componentasyncconfetch(..., { cache: 'no-store' })(App Router). - ¿Tienes páginas que traen información que no cambia mucho, que es cacheable y que está disponible en tiempo de compilación, por ejemplo desde un CMS? R/: Usa
getStaticProps(Pages Router) o un Server Component confetch(..., { cache: 'force-cache' })(App Router). - ¿Lo anterior, pero además la página recibe parámetros? R/: Usa
getStaticPropscongetStaticPaths(Pages Router) ogenerateStaticParams(App Router).
Tip: Next.js sigue mejorando en lo que respecta a la obtención de datos; es de lejos mi parte favorita, ya que tiene poca o ninguna sobrecarga y es extremadamente potente.
Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente, o que simplemente te haya ayudado a entender cuáles son los mecanismos que tiene Next.js para la obtención de datos.
Resumen en 3 puntos
- En el Pages Router, Next.js ofrece
getStaticProps,getStaticPathsygetServerSidePropspara obtener datos del lado del servidor. getStaticPropsygetStaticPathssirven para prerenderizar páginas estáticas y dinámicas en tiempo de compilación, mientras quegetServerSidePropsse usa para el Server Side Rendering en cada request.- En el App Router (Next.js 13 a 16) esas funciones se reemplazan por Server Components
asyncconfetch(controlandocacheyrevalidate) y porgenerateStaticParams. Elige según si necesitas Server Side Rendering, la frecuencia con la que cambian los datos y si la información está disponible en tiempo de compilación.
Déjame un comentario si te sirvió, si quieres añadir alguna opinión o si tienes alguna duda; no dudes en dejarlo en la parte de abajo. Recuerda que si te gustó, también puedes compartir usando los links a las redes sociales en la parte de abajo.
Ejercicios propuestos
- Crea un proyecto básico de Next.js e implementa un ejemplo de
getStaticPropspara traer datos desde un archivo JSON local. - Modifica el proyecto anterior y crea una página con ruta dinámica utilizando
getStaticPathsygetStaticPropspara generar páginas estáticas con datos específicos (recuerda incluir la clavefallback). - Añade al proyecto una función que utilice
getServerSidePropspara obtener datos desde una API externa y muestre los resultados en una página. - Reescribe el ejercicio 2 en el App Router: usa
generateStaticParamsy un Server Componentasyncconfetchpara lograr el mismo resultado. - Implementa una función de paginación en la página donde utilizaste
getServerSidePropspara limitar el número de resultados mostrados y permitir la navegación entre páginas. - Realiza pruebas de rendimiento y compara los tiempos de carga y procesamiento de las páginas utilizando cada método. Analiza en qué casos es más conveniente usar cada uno.
¡Buena suerte con tus ejercicios! No dudes en compartir tus resultados y preguntas en los comentarios. Estaré encantado de ayudarte si tienes alguna duda o dificultad en el proceso. ¡Feliz aprendizaje!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.