Back to blog
Arquitectura de Software reactarquitectura

Arquitectura por Funcionalidades en React (Feature-Based)

SolvedCode Team December 8, 2025 6 m read
Arquitectura por Funcionalidades en React (Feature-Based)

Arquitectura por Funcionalidades en React (Feature-Based)

La arquitectura por funcionalidades (Feature-Based) es uno de los enfoques más utilizados en aplicaciones React en producción, especialmente cuando el producto crece en módulos claros (autenticación, facturación, proyectos, usuarios, etc.). Su principio central es simple: organizar el código por dominio funcional, agrupando en un mismo lugar todo lo que evoluciona junto.

Qué reglas necesita para no degradarse con el tiempo y cómo combinarla con prácticas modernas de React y frameworks como Next.js.


Qué es la arquitectura Feature-Based

En lugar de agrupar por tipo técnico (components/, hooks/, utils/), se agrupa por módulos de negocio. Cada módulo contiene su UI, lógica, estado remoto, validaciones, tipos y pruebas. Esto mejora:

  • Mantenibilidad: se encuentra el código de una funcionalidad en un solo lugar.
  • Escalabilidad: nuevos módulos se agregan sin desordenar el resto.
  • Trabajo en paralelo: los equipos pueden operar con límites más claros.

Estructura recomendada

Una base sólida (y fácil de mantener) suele verse así:

src/
  app/                # bootstrap, providers, rutas, configuración global
  features/           # dominios funcionales (módulos)
    auth/
    projects/
    billing/
    users/
  components/
    ui/               # componentes reutilizables (sin lógica de negocio)
  services/           # clientes HTTP, SDKs, integraciones externas
  lib/                # utilidades transversales (helpers, formatting, etc.)
  types/              # tipos compartidos (si aplica)
  assets/             # recursos estáticos

Por qué esta estructura funciona

  • features/ concentra la evolución del producto: es donde vive el “trabajo real”.
  • components/ui protege la reutilización: evita que componentes “genéricos” terminen acoplados al negocio.
  • services/ centraliza integraciones: elimina llamadas dispersas y facilita cambios (por ejemplo, proveedor de pagos).
  • app/ mantiene la configuración global separada del dominio.

Cómo debe verse un módulo de feature

Ejemplo: src/features/projects/

src/features/projects/
  api/                # requests del dominio (queries/mutations)
  components/         # componentes propios del dominio (no genéricos)
  hooks/              # hooks del dominio
  routes/             # pages o route components del dominio (según framework)
  types/              # tipos del dominio
  utils/              # utilidades internas del dominio
  validation/         # schemas (zod, yup, etc.)
  tests/              # pruebas del dominio (unit/integration)
  index.ts            # export público del módulo

Regla práctica: si algo solo existe por “Projects”, debe vivir dentro del módulo.


Reglas de importación (lo que evita que se rompa)

Feature-Based funciona bien solo si existen límites claros. Estas reglas suelen ser suficientes:

1) components/ui no conoce dominios

Los componentes UI reutilizables no deben:

  • Importar desde features/*
  • Consumir APIs
  • Tener reglas de negocio

Solo reciben props y renderizan.

2) Los módulos de features/ no se importan libremente entre sí

Evita que auth importe cosas internas de billing, o que projects dependa de users sin control.

Si se necesita compartir, hay 3 caminos comunes:

  • Mover algo a lib/ o types/ si es transversal
  • Exponer un contrato estable vía features/x/index.ts
  • Crear una capa compartida explícita (por ejemplo shared/), si el proyecto lo justifica

3) Las integraciones viven en services/

El código de UI no debería conocer URLs, tokens, headers, ni detalles de SDKs.
Eso reduce el costo de cambios y mejora la trazabilidad.


Feature-Based + estado remoto (React Query / SWR)

En aplicaciones modernas, una gran parte del “estado” es realmente estado remoto (servidor). Buenas prácticas:

  • Mantener queries/mutations dentro del dominio:
    • src/features/projects/api/getProjects.ts
    • src/features/projects/api/createProject.ts
  • Evitar duplicar en useState datos que ya gestiona React Query/SWR.
  • Definir claves de caché por dominio (projectsKeys) para invalidación consistente.

Ejemplo conceptual:

// src/features/projects/api/projectsKeys.ts
export const projectsKeys = {
  all: ['projects'] as const,
  list: (filters: Filters) => [...projectsKeys.all, 'list', filters] as const,
  detail: (id: string) => [...projectsKeys.all, 'detail', id] as const
}

Cómo se integra con Next.js o React Router

Hay dos enfoques comunes:

Opción A: rutas en app/ y lógica en features/

  • src/app/routes/* (o app/ en Next.js)
  • Cada ruta usa componentes de features/*

Ventaja: mantiene routing como capa de “ensamble” y deja dominios limpios.

Opción B: rutas dentro de cada feature

  • src/features/projects/routes/*
  • Un router principal compone rutas desde features

Ventaja: cada dominio controla su entrada.
Riesgo: exige disciplina para no duplicar routing y layouts.


Pruebas: el principal beneficio en equipos

Cuando la arquitectura está bien aplicada:

  • Las pruebas del dominio viven con el dominio.
  • La UI genérica tiene pruebas aisladas.
  • Los mocks de integraciones están centralizados.

Sugerencia práctica:

  • Pruebas unitarias para validaciones y utilidades del dominio.
  • Pruebas de integración para flujos críticos (formularios, navegación, permisos).

Errores frecuentes (y cómo evitarlos)

1) “features” se convierte en un nuevo “components”

Síntoma: todo termina en features/common/ o features/shared/ sin criterio.
Solución: lo compartido debe estar justificado y tener dueño (lib/, types/, services/).

2) UI reusable contaminada por negocio

Síntoma: Button conoce permisos, roles o estados internos de un módulo.
Solución: el negocio se resuelve en la feature y se pasa como props.

3) Dependencias circulares entre módulos

Síntoma: auth importa users, users importa auth.
Solución: contratos estables en index.ts, mover tipos a types/, o crear un módulo shared explícito.


Checklist de implementación (para equipos)

  • Cada feature tiene un index.ts con exports públicos (evitar imports internos).
  • components/ui no importa desde features/.
  • Acceso a APIs centralizado en services/.
  • Queries/mutations ubicadas dentro de cada feature.
  • Tipos compartidos en types/ (no duplicados por módulo).
  • Reglas de importación verificadas (idealmente con ESLint boundaries).
  • Documentación corta de “reglas del repo” para nuevos integrantes.

Recomendación empresarial

Para la mayoría de productos que están creciendo, una base equilibrada es:

Feature-Based + UI reutilizable + capa de servicios + reglas de importación

Esto permite evolucionar rápido sin perder control, reduce costos de mantenimiento y facilita que el equipo crezca sin reescribir la base del proyecto.


Conclusión

Feature-Based no es solo una estructura de carpetas. Es una forma de operar: el código se organiza según cómo evoluciona el producto, y se protegen límites para evitar acoplamientos. Cuando se aplica con reglas claras, es una de las arquitecturas más efectivas para React a escala.