Inicio / Artículos

Estado de la URL, estado del servidor y un BFF: una pila Vite para aplicaciones React internas

Por qué una plataforma interna de React autenticada puede beneficiarse más de Vite, TanStack Router, TanStack Query y un BFF separado que de Next.js, y cuándo deja de ser cierto.

Editor: REACTAPP.TOP10 min de lectura2310 palabras

Fuentes: Next.js is excellent. That’s exactly why you **shouldn’t** use it everywhere.

Cuando se inicia un nuevo proyecto React, la pregunta “¿deberíamos usar Next.js?”, suele responderse con un sí antes de que alguien describa la aplicación. Para sitios públicos con mucho contenido, esa reacción suele ser acertada. Pero en una plataforma de operaciones con autenticación, donde los usuarios pasan todo el día filtrando tablas y editando registros tras iniciar sesión, muchas de las características más potentes del framework resuelven problemas que la aplicación en sí no tiene. Este artículo explica la arquitectura que realmente necesita una plataforma de este tipo, muestra cómo un conjunto compuesto por React, Vite, TanStack Router, TanStack Query y un backend-for-frontend (BFF) se adapta a ella, y finaliza con una lista de verificación para decidir cuándo Next.js es, después de todo, la opción más adecuada.

Nada aquí indica que Next.js sea deficiente. Es uno de los mejores frameworks de React disponibles. La crítica se dirige a adoptarlo por defecto, sin verificar si sus capacidades coinciden con los requisitos.

Un escenario concreto

Imaginemos un pequeño equipo de cinco ingenieros que desarrolla una plataforma interna con más de 100 rutas, más de 300 puntos finales de API y aproximadamente un millón de llamadas a la API al mes. Podrían construirla con Next.js, pero en su lugar eligen React con Vite, TanStack Router para la navegación, TanStack Query para manejar los datos, y un BFF separado entre el frontend y los servicios backend. Después de seis meses de desarrollo, esa elección sigue siendo válida, no porque Next.js haya fallado, sino porque la plataforma apenas utiliza las áreas en las que Next.js destaca.

Para una comparación más amplia de los dos enfoques según el tipo de proyecto, consulte Next.js o React simples: adaptar el framework a su proyecto. El enfoque aquí es más específico: qué necesita una aplicación autenticada y con muchos datos de cada capa.

Describa la aplicación antes de elegir el framework

Next.js se ha convertido en la opción estándar porque incluye muchas funcionalidades: enrutamiento y diseños basados en archivos, SSR y Componentes del Servidor, una capa de caché, middleware, código de backend en el mismo proyecto, imágenes optimizadas y un amplio ecosistema. Para muchos productos, esta integración es ideal. Sin embargo, la pregunta más útil es qué tipo de aplicación está creando. Dos aplicaciones con React pueden no tener casi nada en común desde el punto de vista arquitectónico.

Página web pública

Un sitio de comercio electrónico público suele tener:

  • miles de páginas a las que cualquiera puede acceder
  • tráfico proveniente de motores de búsqueda
  • requisitos reales de SEO
  • páginas de productos cuyo contenido se beneficia del renderizado en el servidor
  • URL públicas compartibles y vistas previas en redes sociales
  • mucho contenido estático o que cambia lentamente

Una plataforma de operaciones internas

Una herramienta interna suele tener:

  • casi todas las pantallas tras el proceso de autenticación
  • búsqueda de clientes, filtros y tablas paginadas
  • formularios, paneles de control y verificaciones de permisos
  • mutaciones frecuentes y datos casi en tiempo real
  • una gran cantidad de estado del servidor
  • una interfaz altamente interactiva
  • una capa API o BFF que ya existe

Ambas son aplicaciones React, pero abordan problemas diferentes, y la arquitectura debe reflejar eso.

Los usuarios operan la aplicación en lugar de leerla

En una plataforma interna, un usuario inicia sesión y trabaja dentro de la aplicación durante todo el día. No llega a través de un resultado de búsqueda, no lee artículos ni navega por listas de productos. Busca, filtra, ordena, abre cuadros de diálogo, envía formularios, modifica registros, cambia pestañas, navega por tablas, actualiza datos y pasa de una entidad relacionada a otra. Está utilizando una aplicación, no visitando un sitio web, y ese cambio determina qué características del framework son importantes.

El SEO deja de ser un requisito

Tome una ruta como /customers/12345 que muestre un registro de cliente autenticado con datos sensibles. Usted definitivamente no desea que un motor de búsqueda lo indexe. No hay necesidad de que los rastreadores lo descubran ni de que la primera respuesta HTML sea amigable para ellos. La página es valiosa porque un usuario autorizado interactúa con ella, no porque pueda ser encontrada. Por lo tanto, una de las principales razones para elegir Next.js aporta poco en este contexto. Se trata de una discrepancia entre requisitos, no de un defecto en el framework.

Dónde encajan los componentes del servidor y dónde no

Los componentes del servidor son un modelo realmente útil, por lo que la pregunta merece atención. Imagine una página de operaciones de clientes con varias secciones:

Customer
├── Profile
├── Loans
├── Payments
├── Transactions
├── Documents
└── Activity

En cuanto la página se carga, el usuario comienza a modificarla. Por ejemplo, filtran la lista de pagos:

Status: Failed
Type: ACH
Date: Last 30 days

Luego hacen paginación, ordenan, buscan, abren una transacción y editan algo. La vista se transforma continuamente debido a las entradas del usuario y a los datos frescos del servidor. El flujo dominante no es este ciclo de estilo documento:

Request → Render document → Read document

Está mucho más cerca de un bucle de interacción:

User interaction
       ↓
Application state
       ↓
Server state
       ↓
API
       ↓
Updated UI

Cuanto más se asemejen sus pantallas al segundo diagrama, más determinará la arquitectura del lado cliente la calidad: cómo se almacena el estado, cómo se cachean los datos y cómo reacciona la interfaz de usuario ante los cambios. Los componentes del servidor aún pueden renderizar partes de dicha página, pero no eliminan la necesidad de una capa de datos sólida en el lado cliente.

Tratar la URL como estado de la aplicación

Supongamos que un usuario de operaciones está en la pestaña de pagos de un cliente:

/customer/12345/payments

Aplican un conjunto de filtros:

status=failed
type=ach
amountMin=500
page=2

Si esos filtros están codificados en la dirección, la URL se convierte en:

/customer/12345/payments
  ?status=failed
  &type=ach
  &amountMin=500
  &page=2

En ese punto, la URL ya no es solo un medio de navegación; forma parte del estado de la aplicación. Un ingeniero puede pegarla a un colega, quien llegará al mismo cliente, a la misma pestaña, con los mismos filtros y a la misma página de resultados. También sobrevive a las recargas y hace que el botón de retroceso funcione como lo esperan los usuarios. Lograr esto en múltiples pantallas es precisamente donde un router seguro desde el punto de vista tipológico demuestra su valor.

Qué aporta TanStack Router

TanStack Router trata la enrutación como un elemento fundamental del diseño. Las rutas, los parámetros de ruta y los parámetros de búsqueda pueden expresarse en el sistema de tipos, lo cual es crucial cuando una aplicación tiene más de cien rutas. A esa escala, la enrutación deja de ser simplemente “¿qué componente se renderiza aquí?”; se convierte en parte de la arquitectura. En el caso de una ruta como esta:

/customer/$customerId/payments

se desea:

  • parámetros de ruta claramente definidos y tipados
  • parámetros de búsqueda que están validados y tienen tipos predecibles
  • llamadas de navegación revisadas por el compilador, de modo que un parámetro con nombre diferente interrumpe la compilación en lugar del enlace
  • estados de carga y error declarados por ruta
  • protecciones de autenticación a nivel de ruta
  • enlaces profundos que funcionan siempre
  • Lo importante es que nada de esto depende de si una página se renderiza en un servidor. Para una aplicación interna que funciona completamente en el navegador, esto es muy adecuado.

    El estado del servidor es el verdadero eje central

    Gran parte de una gran aplicación interna se refiere menos a páginas y más a datos remotos. Las entidades que lee y escribe constantemente se ven así:

    Customers
    Loans
    Payments
    Transactions
    Documents
    Users
    Accounts
    Reports
    

    Para cada una de ellas, el frontend debe responder a las mismas preguntas:

    • ¿Estos datos ya están en memoria?
    • ¿Se han vuelto obsoletos?
    • ¿Deberían volverse a obtener, y cuándo?
    • ¿Qué muestra la interfaz de usuario mientras se carga?
    • ¿Qué sucede cuando una solicitud falla?
    • ¿Podría otro componente compartir ese resultado?
    • ¿Qué cambia después de una mutación, y qué consultas deben invalidarse?
    • ¿Qué debería aparecer de inmediato cuando el usuario vuelve atrás?
    • ¿Puede la interfaz de usuario actualizarse de forma optimista?

    Eso es la gestión del estado del servidor, y es precisamente el problema para el cual está diseñado TanStack Query: un caché indexado por consulta, recarga en segundo plano, deduplicación de solicitudes idénticas, ganchos de mutación e invalidación dirigida. Con el router a cargo del estado de la URL y Query a cargo del estado del servidor, cada capa tiene una responsabilidad clara, y el estado local de los componentes se reduce a cuestiones realmente relacionadas con la interfaz de usuario, como si un diálogo está abierto o no.

    Mantener al BFF como límite de la API

    En este escenario, el frontend no llama directamente a docenas de microservicios. Se comunica con un BFF, que a su vez se comunica con los servicios. Esa separación mantiene al frontend ajeno a los detalles de implementación del backend, incluyendo si una respuesta se compone de un servicio o de cinco. El BFF es el responsable del contrato API.

    También permite una división clara en las tareas de despliegue. El frontend consiste en activos estáticos servidos desde un CDN o un servidor estático:

    Frontend
       ↓
    CDN / static hosting
    

    mientras que el BFF funciona como un servicio independiente frente a los microservicios:

    BFF
       ↓
    Microservices
    

    Cada componente puede desarrollarse y publicarse de forma independiente. Next.js puede implementarse sin problemas junto con un BFF. La verdadera pregunta es si tu framework frontend también debe funcionar como límite del servidor. Cuando la organización ya cuenta con una capa backend que proporciona ese límite, agregar otra dentro del framework frontend duplica las responsabilidades.

    La autenticación permanece en el lado del servidor

    El flujo de autenticación sigue manteniendo esta separación. El usuario hace clic en “iniciar sesión” y es redirigido a Okta. Tras un inicio de sesión exitoso, la llamada de retorno llega al backend, que almacena el token de acceso en su lado, mientras Redis se encarga del almacenamiento de sesiones. El navegador solo conserva un identificador de sesión en una cookie segura. Conceptualmente:

    Browser
       │
       │ Sign in
       ▼
     Okta
       │
       │ Callback
       ▼
     BFF / Backend
       │
       ▼
     Redis
    

    La aplicación React no es donde reside la arquitectura de autenticación; su función es operar el producto, mientras que el BFF se encarga de la seguridad y del contrato API. Un efecto secundario útil es que los tokens de acceso nunca llegan al JavaScript del navegador, lo cual reduce el impacto de un error XSS. Hacer esto dentro de Next.js no es intrínsecamente peor, pero cuando esta arquitectura ya existe en la organización, mantenerla fuera del frontend es sencillo y claro.

    Sí, Next.js podría hacer todo esto

    Puede hacerlo. Se podría construir la aplicación con Next.js utilizando componentes cliente, aplicar TanStack Query en su interior, configurar la autenticación, conectarla al BFF y desplegarla como se prefiera. La capacidad no es el problema. La pregunta más relevante es cuánto del framework se utilizaría realmente. Si la mayor parte de la aplicación termina viéndose así:

    'use client'
            ↓
    Client-side interactions
            ↓
    API calls
            ↓
    TanStack Query
    

    Entonces vale la pena detenerse a preguntarse si las funcionalidades del lado servidor justifican hacer de Next.js el límite de su aplicación, con sus convenciones, entorno de ejecución y ruta de actualización.

    Cada componente de la pila componible tiene una función

    Para este tipo de aplicaciones, una configuración por defecto razonable es React, Vite, TanStack Router y TanStack Query, además del BFF. No se trata de unir bibliotecas hasta construir accidentalmente su propio framework. Cada componente tiene un papel definido:

    • Vite proporciona las herramientas de compilación y el servidor de desarrollo.
    • React renderiza la interfaz de usuario.
    • TanStack Router se encarga del enrutamiento y del estado de las URL.
    • TanStack Query gestiona el estado del servidor.
    • El BFF constituye el límite de la API y de la seguridad.

    Dado que las responsabilidades son claras, se puede reemplazar una parte sin tener que replantear toda la aplicación.

    Las desventajas de excluir Next.js

    La ruta composable conlleva ciertos costos. Debes renunciar a la experiencia que ofrece Next.js por defecto y tomar decisiones que normalmente él haría por ti: la estructura del proyecto, las convenciones de división del código, cómo el host estático maneja las rutas del lado del cliente y mantener actualizadas varias bibliotecas al mismo tiempo. Los requisitos también pueden cambiar. Si luego la mitad de la aplicación necesita hacerse pública y el SEO se vuelve importante de repente, Next.js resulta mucho más atractivo. Lo mismo ocurre si necesitas renderizado en servidor o generación estática en gran escala, si los Componentes de Servidor aportan un valor real a tu diseño, o si realmente deseas que el código del frontend y del servidor estén vinculados intencionadamente en una sola implementación. Por lo tanto, la decisión no es “Next.js o React”, sino cuál arquitectura se adapta mejor a la aplicación.

    Una lista de verificación para elegir

    Antes de decidirte, revisa estas preguntas:

    • ¿La aplicación tiene una interfaz pública significativa? Eso es una ventaja importante para Next.js.
    • ¿Es importante el SEO? Next.js se vuelve aún más atractivo en este aspecto.
    • ¿Necesita renderizado en servidor o generación estática? Next.js también gana en esta situación.
    • ¿Mejorarían significativamente el diseño los Componentes de Servidor o las Acciones de Servidor? Entonces considere seriamente a Next.js.
    • ¿La aplicación es principalmente autenticada y altamente interactiva? Opte por React con Vite.
    • ¿La organización ya utiliza una capa BFF o API? Vale la pena considerar una aplicación cliente independiente desplegada por separado.
    • ¿El estado del servidor es una preocupación principal? TanStack Query se vuelve muy atractivo en este caso.
    • ¿El estado de las URL y el enrutamiento complejo son cruciales? TanStack Router se vuelve muy atractivo también.

    De estas respuestas se deriva una regla práctica sencilla. Cuando una aplicación tiene una gran superficie expuesta al público, considere seriamente Next.js. Cuando está predominantemente protegida por autenticación, especialmente si se trata de una plataforma interna o de administración, comience con React y Vite y añada únicamente las partes que necesite. En general, ninguna de estas tecnologías es mejor; una es más adecuada para un problema específico, distinción que fácilmente se pierde cuando un framework se convierte en la opción por defecto.

    Conclusión

    La mejor arquitectura no es la que cuenta con la lista de funcionalidades más larga, sino aquella cuyas características resuelven los problemas reales que se tienen. Para una herramienta de operaciones con acceso restringido mediante inicio de sesión, respaldada por su propia capa backend, con estado del servidor intensivo, interacciones frecuentes y muy poco contenido público, React junto con Vite, TanStack Router y TanStack Query no representa un compromiso; es una elección deliberada.

    • Clasifique primero la aplicación: sitio de contenido público o herramienta con autenticación.
    • Trate la URL y los datos del servidor como los dos principales almacenes de estado, y asigne una herramienta dedicada a cada uno.
    • Mantenga los límites de seguridad y API donde su organización ya los tenga establecidos.
    • Vuelva a considerar la decisión si las páginas públicas, el SEO o el renderizado en servidor se convierten en requisitos reales.