Lección 13 de 15 · Lectura y práctica
Estructura de proyecto escalable
CONCEPTO CLAVE: Una estructura de proyecto escalable en React no es solo organizar archivos, es crear una arquitectura que permita que tu aplicación crezca sin volverse un caos. La forma en que organizas tu código hoy determinará.
Del concepto a la práctica
Taller de esta lección
Explicación
Una estructura por características agrupa archivos que cambian juntos. El criterio no es crear muchas carpetas, sino hacer visible qué módulo posee una regla y limitar importaciones entre áreas.
Ejemplo resuelto
src/
features/reservas/{ReservaForm.jsx,reservasLogic.js}
features/catalogo/{Catalogo.jsx,datos.js}
shared/{Button.jsx,formatos.js}La validación de reservas pertenece a reservasLogic.js; shared contiene piezas sin conocimiento del dominio.
Pruébalo
Lista tres responsabilidades actuales.
Asígnalas a una característica o a
shared.Revisa cada importación cruzada.
Error frecuente: crear una carpeta utils para todo; corrígelo colocando cada función junto a su dominio si no es realmente transversal.
Comprueba tu resultado
Ejercicio: ubica formatearFecha, validarReserva y BotonPrimario. Resultado esperado: formatearFecha en shared solo si es genérica, validarReserva en reservas y BotonPrimario en shared. Escribe una dependencia permitida por cada archivo.

Mapa de prácticaUna condición decide qué camino ejecuta el programa. Un bucle repite una operación mientras queden elementos, y termina cuando la lista se agota. Separar ambas ideas ayuda a seguir el flujo y comprobar casos límite.
Ver la infografía en tamaño completo ↗¿Por qué importa la estructura de proyecto?
Cuando trabajas en proyectos pequeños, podrías pensar que no necesitas una estructura elaborada. Pero la realidad es que los proyectos crecen, los equipos se expanden, y lo que hoy tiene 5 componentes mañana puede tener 500.
Una buena estructura de proyecto te ofrece:
- Orientación rápida: Cualquier desarrollador nuevo encuentra lo que busca en segundos.
- Escalabilidad real: Agregar funcionalidades sin romper existente.
- Mantenimiento sencillo: Cambios localizados sin efectos secundarios inesperados.
- Colaboración efectiva: Equipos que trabajan en paralelo sin conflictos.
Estructura recomendada para proyectos escalables
No existe una única estructura perfecta, pero existe una que funciona mejor que la mayoría: la estructura por características o feature-based structure.
Estructura base
src/
├── assets/ # Imágenes, fuentes, archivos estáticos
├── components/ # Componentes reutilizables globales
│ ├── common/ # Botones, inputs, cards, etc.
│ ├── layout/ # Header, Footer, Sidebar
│ └── ui/ # Componentes de interfaz específicos
├── features/ # Funcionalidades de dominio
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ ├── types/
│ │ └── index.ts
│ ├── dashboard/
│ └── users/
├── hooks/ # Hooks globales y personalizados
├── lib/ # Utilidades y configuraciones
├── services/ # Llamadas API y configuración
├── store/ # Estado global (Redux, Zustand, etc.)
├── styles/ # Estilos globales y temas
├── types/ # Tipos TypeScript globales
├── utils/ # Funciones auxiliares
├── App.tsx
└── main.tsxfeatures es el corazón de esta estructura. Cada funcionalidad vive en su propio espacio, conteniendo todo lo que necesita para funcionar de forma independiente.El patrón de arquitectura Feature-Sliced Design
Una evolución natural de la estructura por características es el patrón Feature-Sliced Design (FSD). Este enfoque organiza el código en capas jerárquicas:
| Capa | Descripción | Ejemplos |
|---|---|---|
| app/ | Configuración global, providers, routing | App.tsx, providers.tsx, routes.tsx |
| pages/ | Rutas principales de la aplicación | DashboardPage, ProfilePage |
| widgets/ | Bloques de UI compuestos independientes | UserCardWidget, StatsWidget |
| features/ | Acciones de usuario específicas | AddToCart, SearchUsers, SendMessage |
| entities/ | Entidades de negocio (modelos) | User, Product, Order |
| shared/ | Código sin dependencia de negocio | Button, Modal, api.ts |
components/. Un componente UserCard.tsx en components/ viola los principios de separación. Debe estar en entities/user/.Organizando un módulo de funcionalidad
Veamos cómo se ve un módulo bien estructurado en la práctica:
src/features/users/
├── api/
│ └── usersApi.ts # Endpoints específicos
├── components/
│ ├── UserList/
│ │ ├── UserList.tsx
│ │ ├── UserList.styles.ts
│ │ └── UserList.test.tsx
│ ├── UserCard/
│ │ ├── UserCard.tsx
│ │ └── UserCard.styles.ts
│ └── UserForm/
│ └── UserForm.tsx
├── hooks/
│ ├── useUsers.ts
│ └── useUserById.ts
├── types/
│ ├── user.types.ts
│ └── user.dto.ts
├── utils/
│ └── userHelpers.ts
├── constants/
│ └── userConstants.ts
├── selectors/
│ └── userSelectors.ts # Para Zustand/Redux
├── services/
│ └── userService.ts # Lógica de negocio
├── index.ts # Exports públicos
└── users.slice.ts # Estado local (si aplica)Ver más: Ejemplo de barrel export (index.ts)
// src/features/users/index.ts
export { UserList } from './components/UserList';
export { UserCard } from './components/UserCard';
export { UserForm } from './components/UserForm';
export { useUsers, useUserById } from './hooks';
export type { User, UserDTO, CreateUserPayload } from './types';
export { userService } from './services/userService';Patrones de nomenclatura esenciales
La consistencia en nombres es tan importante como la estructura:
- Archivos de componentes: PascalCase (
UserCard.tsx) - Archivos de hooks: camelCase con prefijo use (
useUsers.ts) - Archivos de estilos: Mismo nombre + extensión (.styles.ts, .module.css)
- Archivos de tests: Mismo nombre + .test.tsx
- Constantes: SCREAMING_SNAKE_CASE
- Tipos/Interfaces: PascalCase, sufijos descriptivos (UserDTO, CreateUserPayload)
«El código se escribe una vez, pero se lee cientos de veces. Nombres claros son documentación implícita.» — Robert C. Martin
Configuración de imports absolutos
Para mejorar la legibilidad, configura imports absolutos en tu proyecto:
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"],
"@features/*": ["src/features/*"],
"@hooks/*": ["src/hooks/*"],
"@utils/*": ["src/utils/*"],
"@lib/*": ["src/lib/*"],
"@store/*": ["src/store/*"],
"@types/*": ["src/types/*"]
}
}
}Así en lugar de escribir:
import { Button } from '../../../components/common/Button';Escribes:
import { Button } from '@components/common/Button';vite-tsconfig-paths para que el servidor de desarrollo reconozca los mismos paths.Separación de concerns por contexto
No todo debe estar en components/. Aprende a separar:
| Concern | Ubicación | Ejemplo |
|---|---|---|
| Lógica de UI | components/ | UserCard.tsx renderiza props |
| Lógica de negocio | features/*/services/ | calculateDiscount() |
| Acceso a datos | features/*/api/ | fetchUsers() |
| Estado global | store/ | authSlice, userSlice |
| Estado local | hooks/ | useToggle, useLocalStorage |
Migrando un proyecto existente
Si tienes un proyecto con estructura plana o caótica, la migración gradual es posible:
- Identifica dominios: Agrupa archivos por funcionalidad real.
- Crea la estructura: Añade las carpetas vacías.
- Mueve incrementalmente: Un módulo a la vez, verificando tests.
- Actualiza imports: Usa herramientas como
change-caseo scripts de migración. - Refactoriza al mover: No solo mover, también mejora.
- Documenta: Crea un README con la guía de estructura.
Checklist de estructura saludable
Antes de considerar tu estructura completa, verifica:
- ¿Cada archivo tiene una única responsabilidad clara?
- ¿Los componentes reutilizables están en
shared/ocomponents/? - ¿Las funcionalidades de negocio viven en
features/? - ¿Los archivos barril (
index.ts) exponen solo lo público? - ¿Los paths de imports son consistentes (absolutos o relativos)?
- ¿Los tests están junto al código que prueban?
- ¿La profundidad de carpetas no excede 4 niveles?
Según el patrón Feature-Sliced Design, ¿en qué capa se ubicaría un componente de botón reutilizable globalmente?
- A) entities/
- B) features/
- C) shared/
- D) widgets/
shared/ ya que son elementos reutilizables universales.Conclusión
La estructura de proyecto no es un documento decorativo, es la arquitectura que sostiene el crecimiento de tu aplicación. Invierte tiempo en diseñarla correctamente al inicio y te ahorrará meses de refactoring dolorosos después.
Recuerda: la mejor estructura es aquella que tu equipo entiende, respeta y puede navegar sin esfuerzo. Adáptala a tu contexto, tu equipo y tu aplicación específica.
Sigue con React Intermedio: Dominando Componentes y Patrones Avanzados
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.