Web Standards Framework

Remix

Remix es el framework de React centrado en los estándares web. Se apoya en HTTP, formularios y mejora progresiva para que tu aplicación funcione incluso antes de que llegue el JavaScript.

intermediate13 min readUpdated 15 sept 2026
posts.$slug.tsx
tsx
// app/routes/posts.$slug.tsx
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

export async function loader({ params }) {
  const post = await getPost(params.slug);
  if (!post) throw json({ message: "Not found" }, { status: 404 });
  return json({ post });
}

export default function Post() {
  const { post } = useLoaderData();
  return <article>{post.title}</article>;
}
Construido sobre
React
Modelo
Nested routes
Datos
loaders
Mutaciones
actions
Filosofía
Web standards first
Actualidad
Fusionado en React Router v7

Por que importa

Por qué Remix toma un camino diferente

Mejora progresiva

Los formularios y la navegación funcionan sin JavaScript, y luego se vuelven más rápidos y fluidos una vez que este se carga.

Rutas anidadas con datos

Cada ruta carga sus propios datos y gestiona sus propios errores, en paralelo con sus rutas hermanas.

Menos piezas móviles

Los loaders y actions reemplazan la habitual maraña de estado del cliente, efectos y llamadas a la API.

La imagen completa

Las tres ideas detrás de Remix

Las rutas son dueñas de sus datos, las mutaciones son formularios y todo se degrada elegantemente sin JavaScript.

Rutas

Estructura

Las rutas anidadas definen la URL, el layout y el límite de datos en un solo lugar.

Loaders y actions

Datos

Funciones de servidor que leen datos antes del renderizado y gestionan mutaciones desde formularios.

Estándares web

Fundamento

Las peticiones, respuestas, formularios y cabeceras son primitivas de la plataforma, no abstracciones del framework.

Remix de un vistazo

El núcleo de Remix

Rutas anidadas

Los módulos de ruta se anidan para coincidir con la jerarquía de la UI y cargan datos en paralelo.

Loaders

Funciones de servidor que proporcionan datos a una ruta antes de que se renderice.

Actions

Funciones de servidor que gestionan el envío de formularios y las mutaciones.

Formularios

Formularios HTML reales que funcionan sin JavaScript y se mejoran automáticamente.

Error boundaries

Gestión de errores por ruta que mantiene vivo el resto de la página.

Resource routes

Rutas que devuelven datos en lugar de UI, útiles para APIs y webhooks.

Una breve historia

De un Remix de la web a React Router

  1. 2020

    Anuncio de Remix

    Los creadores de React Router presentan un framework construido sobre estándares web.

    20
  2. 2021

    Código abierto

    Remix se lanza públicamente y gana atención por su modelo de carga de datos.

    21
  3. 2022

    Remix 1.0 y Shopify

    Lanzamiento de la versión estable y Shopify adquiere al equipo y adopta Remix.

    22
  4. 2024

    React Router v7

    Las ideas de Remix se integran en React Router, y Remix se convierte en su modo framework.

    24
  5. Hoy

    React centrado en estándares

    El modelo perdura como el modo framework de React Router, manteniendo la misma filosofía.

    Hoy

La guia completa

Remix: Todo lo que necesitas saber

¿Qué es Remix?

Remix es un framework de React construido sobre estándares web. Mientras que muchos frameworks abstraen la plataforma, Remix se apoya en ella: las solicitudes y respuestas HTTP, los formularios HTML, los enlaces, los headers y las cookies son la base, y el framework los potencia en lugar de reemplazarlos.

El resultado es una aplicación que funciona antes de que JavaScript se cargue. Los formularios se envían, los enlaces navegan y los datos aparecen porque el servidor se encarga del trabajo. Cuando JavaScript finalmente llega, esas mismas interacciones se vuelven instantáneas y parciales. Esta propiedad se llama progressive enhancement (mejora progresiva) y es la idea definitoria de Remix.

En 2024, el equipo de Remix integró el framework en React Router v7, donde ahora reside como “framework mode”. Los conceptos y las APIs se mantienen iguales, por lo que todo lo expuesto aquí se aplica a ambos.

Rutas anidadas

Las rutas son archivos dentro de app/routes, y los puntos en los nombres de los archivos se mapean a segmentos de la URL.

app/routes/
├── _index.tsx              # /
├── posts._index.tsx        # /posts
├── posts.$slug.tsx         # /posts/:slug
├── posts.$slug.edit.tsx    # /posts/:slug/edit
└── api.health.tsx          # /api/health

Las rutas se anidan para coincidir con la UI. Una ruta padre renderiza el layout compartido y un <Outlet />, y las rutas hijas se renderizan dentro de este. Debido a que Remix conoce todo el árbol de rutas, puede cargar los datos de una página y de todas sus rutas anidadas en paralelo en lugar de hacerlo en cascada (waterfall).

// app/routes/posts.tsx
import { Outlet } from "@remix-run/react";

export default function PostsLayout() {
  return (
    <div className="posts">
      <h1>Posts</h1>
      <Outlet />
    </div>
  );
}

Loaders

Un loader es una función del servidor que proporciona datos a una ruta antes de que se renderice. Se ejecuta en el servidor, por lo que puede comunicarse directamente con una base de datos.

// app/routes/posts.$slug.tsx
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

export async function loader({ params }: LoaderFunctionArgs) {
  const post = await getPost(params.slug);
  if (!post) throw json({ message: "Post not found" }, { status: 404 });
  return json({ post });
}

export default function Post() {
  const { post } = useLoaderData<typeof loader>();
  return <article>{post.title}</article>;
}

No hay que gestionar estados de carga ni realizar peticiones en el cliente. Remix llama al loader en el servidor para el renderizado inicial y nuevamente durante la navegación, y el componente recibe los datos de forma síncrona.

Acciones y formularios

Las mutaciones se gestionan mediante actions, que son funciones del servidor vinculadas a una ruta y que se activan al enviar formularios.

// app/routes/posts.new.tsx
import { redirect } from "@remix-run/node";
import { Form } from "@remix-run/react";

export async function action({ request }: ActionFunctionArgs) {
  const data = await request.formData();
  const title = String(data.get("title") ?? "").trim();

  if (!title) return json({ error: "Title is required" }, { status: 400 });

  await createPost(title);
  return redirect("/posts");
}

export default function NewPost() {
  return (
    <Form method="post">
      <input name="title" required />
      <button type="submit">Create</button>
    </Form>
  );
}

Al tratarse de un formulario real, funciona sin JavaScript. Remix intercepta el envío cuando el cliente está listo y revalida automáticamente los loaders afectados, de modo que la UI refleja los nuevos datos sin necesidad de actualizar la caché manualmente.

Error boundaries

Cada ruta puede exportar un ErrorBoundary que captura los errores de su loader, action o componente.

// app/routes/posts.$slug.tsx
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";

export function ErrorBoundary() {
  const error = useRouteError();

  if (isRouteErrorResponse(error) && error.status === 404) {
    return <h1>Post not found</h1>;
  }

  return <h1>Something went wrong</h1>;
}

Los boundaries están anidados, por lo que un error en una ruta hija no deja la página entera en blanco. El layout circundante sigue siendo funcional, lo cual ofrece una experiencia mucho mejor que una pantalla blanca.

Rutas de recurso y estándares web

Una ruta sin exportación predeterminada es una ruta de recurso: devuelve datos en lugar de UI, lo cual es ideal para APIs y webhooks.

// app/routes/api.health.tsx
export async function loader() {
  return json({ status: "ok", time: Date.now() });
}

Debido a que Remix utiliza los estándares Request y Response de la plataforma, puedes leer headers, establecer cookies, transmitir respuestas y devolver cualquier código de estado sin tener que aprender una API específica del framework. Ese conocimiento se transfiere directamente a otros runtimes.

Por qué el modelo se siente diferente

La mayoría de las aplicaciones de React gestionan los datos en effects y los mantienen en el estado del cliente, para luego sincronizar ese estado con el servidor a través de rutas de API. Remix simplifica esas capas:

  • La ruta es dueña de sus datos a través de un loader.
  • La ruta es dueña de sus mutaciones a través de un action.
  • El servidor posee la fuente de verdad y el cliente se mantiene ligero.

Menos piezas móviles significan menos bugs, menos estado que sincronizar y menos código que escribir. La contrapartida es una postura más definida sobre cómo fluyen los datos, que es precisamente la razón por la cual los equipos que lo adoptan suelen preferirlo.

Mejores prácticas

  • Obtén los datos en loaders, no en effects.
  • Realiza mutaciones a través de actions y forms, y deja que Remix se encargue de la revalidación.
  • Utiliza Form y Link de Remix para que la mejora progresiva funcione automáticamente.
  • Exporta un ErrorBoundary en las rutas que puedan fallar.
  • Mantén las rutas anidadas alineadas con la jerarquía de la UI.
  • Utiliza resource routes para APIs y webhooks.
  • Devuelve los códigos de estado y headers adecuados desde los loaders y actions.

Errores comunes

  • Hacer fetch en useEffect en lugar de un loader y perder el renderizado del servidor.
  • Usar fetch para mutaciones en lugar de una action y revalidar manualmente.
  • Olvidar el <Outlet /> en una ruta de layout padre.
  • Silenciar errores en lugar de dejar que los boundaries los gestionen.
  • Hacer over-fetching en un loader padre cuando una ruta hija debería ser la dueña de los datos.
  • Tratar Remix como una SPA de lado del cliente y luchar contra su modelo de servidor.

Próximos pasos

Remix es la expresión más sólida de “use the platform” en el mundo de React. Compáralo con Next.js para conocer el otro enfoque principal de React, y con SvelteKit para ver una filosofía similar en otro ecosistema. Refuerza tus bases de React, TypeScript y Node.js, y luego construye una aplicación pequeña que incluya un loader, un action y un error boundary.

Carga de datos

Un loader se ejecuta en el servidor antes de que la ruta se renderice. No hay estado de carga ni petición desde el cliente.

Preferir
export async function loader() {
  return json({
    posts: await getPosts(),
  });
}

export default function Posts() {
  const { posts } = useLoaderData();
  return <List items={posts} />;
}
Evitar
export default function Posts() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    fetch("/api/posts")
      .then((r) => r.json())
      .then(setPosts);
  }, []);
  return <List items={posts} />;
}

Gestión de mutaciones

Una action gestiona el formulario en el servidor. El mismo formulario funciona con o sin JavaScript.

Preferir
export async function action({ request }) {
  const data = await request.formData();
  await createPost(data.get("title"));
  return redirect("/posts");
}

<Form method="post">
  <input name="title" />
  <button>Create</button>
</Form>
Evitar
async function onSubmit(e) {
  e.preventDefault();
  await fetch("/api/posts", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Remix?

Nuestro tutorial interactivo te guia a traves de Remix paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.