Escalar un ecommerce Magento 2 a 15 tiendas y 9 idiomas desde una sola instancia no es un ejercicio teórico. Es un proyecto real que desarrollamos para Loviux, una ecommerce de bienestar íntimo que opera en toda Europa. Este artículo documenta las decisiones técnicas, los problemas que encontramos y cómo los resolvimos.
Si trabajas con Magento a escala — como CTO, tech lead o developer senior — aquí encontrarás lo que aprendimos al migrar de Luma a Hyvä, construir un checkout custom sin frameworks pesados, automatizar la generación de contenido para +9.000 productos y mantener un stack de rendimiento que no se cae en deploy.
Por qué migrar de Luma a Hyvä (y qué cambia realmente)
Luma fue el frontend por defecto de Magento 2 durante años. Y durante años, fue también su mayor lastre técnico.
El coste real de mantener Luma
El stack de Luma se basa en RequireJS para la carga de módulos y Knockout.js para el data binding. Ambas son tecnologías de 2013 que Magento heredó y nunca modernizó. El resultado práctico en un proyecto con 15 tiendas:
- RequireJS genera una cascada de peticiones HTTP que bloquea el rendering. En un catálogo con miles de productos, cada página cargaba entre 40 y 60 archivos JS antes de ser interactiva.
- Knockout.js añade peso sin aportar valor. Para un ecommerce donde la interactividad real se limita al carrito, filtros y checkout, tener un framework de data binding completo es sobreingeniería.
- El CSS de Luma pesa ~300 KB sin comprimir. Cada personalización añade capas sobre capas de LESS que nadie se atreve a refactorizar.
En nuestras pruebas, una página de categoría en Luma tardaba 4,2 segundos en LCP (Largest Contentful Paint) en móvil. Inaceptable para un ecommerce donde cada segundo extra de carga reduce la conversión un 7% según datos de Google.
Qué ganamos con Hyvä + Tailwind CSS
Hyvä reemplaza todo el frontend de Luma por una arquitectura moderna: Alpine.js para interactividad, Tailwind CSS para estilos y cero dependencias legacy.
Los números tras la migración:
No es una mejora incremental. Es un cambio de orden de magnitud. Y en un multi-store con 15 tiendas, esa diferencia se multiplica: menos recursos de servidor por request, mejor caché, mejor experiencia en cada uno de los 9 idiomas.
La migración no fue trivial. Cada módulo de terceros que usaba Luma (y teníamos más de 30) necesitó un compatibility module para Hyvä o un reemplazo. Documentamos cada dependencia antes de empezar y priorizamos por impacto en el negocio. Los módulos que solo tocaban el admin no necesitaron cambios; los que tenían templates .phtml de frontend, sí.
Multi-store a escala: 15 tiendas, 9 idiomas, una instancia
Magento soporta multi-store de forma nativa, pero la realidad de gestionarlo a escala es otra cosa.
Arquitectura de websites, stores y store views
El setup de Loviux tiene 3 niveles:
- Websites: agrupan tiendas por zona de precios e impuestos (EU sur, EU norte, UK)
- Stores: una por país (España, Francia, Alemania, Italia, Países Bajos, Portugal, Polonia, Austria, Suiza, Bélgica, Reino Unido, más variantes)
- Store views: la capa de idioma. Un store puede tener múltiples views (Suiza tiene 3: DE, FR, IT; Bélgica tiene 2: NL, FR)
En total, 15 store views sirviendo contenido en 9 idiomas: español, inglés, portugués, francés, alemán, italiano, neerlandés, polaco y las variantes regionales.
Sistema de fallback de idioma custom
Aquí encontramos el primer reto real. Magento tiene un fallback de traducciones básico, pero no resuelve el problema del contenido de catálogo.
El problema: cuando un producto no tiene descripción traducida al alemán de Austria (de_AT), Magento muestra un campo vacío. No cae automáticamente al alemán estándar (de_DE). Esto significa que sin un sistema de fallback, necesitas traducir cada producto individualmente para cada locale, incluyendo variantes que comparten idioma.
Nuestra solución: construimos un plugin que intercepta la carga de atributos localizados y aplica una cadena de fallback configurable:
El resultado: las variantes de país heredan automáticamente el contenido del idioma principal. Solo necesitas traducir una vez por idioma, y las diferencias regionales (precios, disponibilidad, textos legales) se gestionan a nivel de store sin duplicar el catálogo completo.
Este mecanismo redujo el esfuerzo de traducción en un 65% y eliminó el riesgo de tener miles de productos con campos vacíos en tiendas secundarias.
Checkout custom con Magewire y Alpine.js
El checkout es donde un ecommerce gana o pierde dinero. El checkout por defecto de Magento 2 (basado en Knockout.js + UI Components) es funcional pero pesado, lento y difícil de personalizar.
Por qué descartamos React y Knockout
Evalamos tres opciones:
- Checkout Luma stock: descartado porque estábamos migrando a Hyvä y mantener Knockout solo para checkout era incoherente.
- Checkout con React (como Hyvä Checkout): añade una dependencia extra de ~130 KB y un build pipeline separado. Para un formulario de 3 pasos, es desproporcionado.
- Magewire + Alpine.js: misma stack que el resto de Hyvä. Sin dependencias extra, sin build pipeline adicional, sin conflictos de estado entre frameworks.
Elegimos Magewire. Es un port de Laravel Livewire para Magento que permite construir componentes interactivos con PHP en el servidor y Alpine.js en el cliente. El resultado es un checkout que pesa menos de 15 KB de JS (sin contar Alpine, que ya está cargado globalmente).
Arquitectura de 3 columnas
Diseñamos el checkout en un layout de 3 columnas en desktop:
- Columna izquierda: dirección de envío y datos del cliente
- Columna central: métodos de envío y pago
- Columna derecha: resumen del pedido, cupones, totales
Los tres paneles se renderizan en servidor con Magewire y se actualizan vía AJAX cuando el usuario cambia datos. No hay SPA, no hay router de cliente, no hay estado compartido que gestionar entre frameworks. Cada componente Magewire es independiente y se comunica con el backend directamente.
En móvil, las columnas colapsan a un flujo vertical con acordeones. El mismo código, sin duplicación ni media queries de layout complejo.
Resultado: el checkout carga en 1,1 segundos en móvil (LCP) y la tasa de abandono en el paso de pago bajó un 12% respecto al checkout anterior con Luma.
Catálogo de +60.000 productos con búsqueda avanzada
Un catálogo de este tamaño necesita más que el search nativo de Magento (MySQL FULLTEXT). Necesita búsqueda facetada rápida y relevante. Basta con su catálogo de vibradores para entender la escala.
SmileElasticSuite con OpenSearch
Implementamos SmileElasticSuite, la solución de búsqueda open source más madura para Magento, conectada a OpenSearch 2.x como motor de indexación.
Configuración clave:
- Faceted search con filtros dinámicos por categoría: los filtros disponibles cambian según la categoría actual (talla, color, material, marca, rango de precio)
- Autocomplete con sugerencias de productos, categorías y términos de búsqueda
- Sinónimos por idioma: configurados por store view para que "gel lubricante" y "lubricante íntimo" devuelvan los mismos resultados
- Relevancia ajustada: boost de productos con stock, con imagen y con reviews por encima de los demás
La reindexación completa del catálogo (60.000+ productos × 9 idiomas) tarda 8 minutos con un cron dedicado. Las actualizaciones incrementales (precio, stock) se procesan en menos de 30 segundos.
Sincronización de stock con proveedores
Loviux trabaja con múltiples proveedores que envían feeds de stock en formatos heterogéneos: XML, CSV y en un caso, un endpoint JSON personalizado.
Construimos un sistema de importación modular:
- Parsers por proveedor: cada proveedor tiene un adapter que normaliza su feed al formato interno (SKU, cantidad, precio coste, ETA)
- Ejecución diaria programada: un cron de Magento ejecuta la sincronización cada noche a las 3:00 AM (hora de menor tráfico)
- Logs y alertas: si un proveedor no envía feed o el formato cambia, se notifica al equipo vía email
- Stock agregado: para productos dropship, el stock visible es la suma de todos los proveedores que lo sirven
Este sistema procesa ~15.000 líneas de stock cada noche sin impacto en el rendimiento del frontend.
Pipeline de contenido con IA: 9.000 productos en 9 idiomas
Aquí está posiblemente el reto más interesante del proyecto. Con +9.000 productos que necesitan descripción en 9 idiomas, estamos hablando de 81.000 textos de producto. Hacerlo manualmente no es viable ni económica ni temporalmente.
El pipeline de 4 pasos
Diseñamos un pipeline automatizado con GPT-4o-mini (elegido por su relación coste/calidad para generación masiva):
Paso 1 — Extracción de features: leemos las fichas técnicas del fabricante (nombre, ingredientes, volumen, tipo de producto, características especiales) y las estructuramos en un JSON normalizado.
Paso 2 — Generación nativa por idioma: en lugar de generar en español y traducir, generamos directamente en cada idioma destino. La diferencia es notable: un texto generado en francés nativo suena natural; uno traducido del español suena a traducción. El prompt incluye contexto de marca, tono y restricciones legales del mercado destino.
Paso 3 — Limpieza: eliminamos frases genéricas repetitivas ("este producto es perfecto para..."), corregimos inconsistencias entre idiomas (un producto no puede ser "150 ml" en España y "5 oz" en Francia si vendemos en ml en toda Europa) y aplicamos reglas de estilo.
Paso 4 — Validación automática: cada texto generado pasa por checks de longitud mínima/máxima, presencia de keywords de producto, ausencia de alucinaciones (ingredientes inventados, características falsas) y formato HTML correcto para Magento.
Números del pipeline
- Coste total: ~420 € en tokens de API para los 81.000 textos
- Tiempo de procesamiento: 14 horas para la generación completa
- Tasa de aprobación automática: 87% de los textos pasaron validación sin intervención manual
- Revisión manual: el 13% restante requirió ajustes menores (principalmente productos con características especiales no cubiertas por las features del fabricante)
Comparado con traducción profesional (estimado en +120.000 € y 4-6 meses), el pipeline de IA representó un ahorro del 99,6% en coste y del 95% en tiempo. La calidad no es la de un copywriter senior, pero para descripciones de producto funcionales y SEO-ready, es más que suficiente.
Stack de rendimiento: Varnish, Redis, OPcache y PHP 8.4
El resultado habla por sí solo: PageSpeed Insights 100 en móvil para un Magento 2 con 15 store views y más de 60.000 productos. FCP de 1,4 segundos, LCP de 1,5 segundos, TBT de 30 ms y CLS de 0. Estos números son excepcionales para cualquier ecommerce, y más aún para uno construido sobre Magento.

El rendimiento en un ecommerce no es opcional. Un sitio lento pierde ventas. Con 15 tiendas sirviendo tráfico de toda Europa, el stack necesita ser sólido.
Arquitectura de caché
La configuración de desarrollo Magento que montamos para Loviux sigue una jerarquía de 4 capas:
- Varnish 7.x como reverse proxy: cachea páginas completas. Un hit de Varnish sirve una página en <10ms sin tocar PHP. Configuramos VCL custom para purge selectivo por store view, categoría y producto.
- Redis para caché de aplicación y sesiones: elimina accesos a disco. Dos instancias separadas: una para caché de configuración/bloques (DB 0) y otra para sesiones (DB 2).
- OPcache de PHP 8.4: precompila los ~40.000 archivos PHP de Magento. Con
opcache.jit=tracinghabilitado, las funciones hot path se compilan a código máquina nativo. - Caché de full page en Magento como fallback para requests que bypasean Varnish (usuarios logueados, carrito no vacío).
CSS bloqueante: una decisión contraintuitiva para CLS 0
La sabiduría convencional dice: carga CSS de forma asíncrona, extrae critical CSS inline. Nosotros hicimos lo contrario. Todo el CSS se carga de forma bloqueante en el <head>.
¿Por qué? Porque con Hyvä + Tailwind, el CSS total es ~35 KB (gzipped: ~8 KB). Cargarlo bloqueante añade unos milisegundos al First Contentful Paint, pero garantiza que el layout nunca cambia después del primer render. El resultado: CLS (Cumulative Layout Shift) de 0.000 consistente en todas las páginas.
En un proyecto con decenas de templates diferentes (home, categoría, producto, checkout, CMS pages × 15 tiendas), mantener un sistema de critical CSS sincronizado sería una pesadilla de mantenimiento. Con 8 KB de CSS bloqueante, el trade-off no tiene sentido.
Deploy zero-downtime con symlink switching
El deploy en producción sigue un flujo que evita downtime:
- Build en directorio temporal (
/var/www/releases/YYYYMMDD-HHMMSS/) composer install --no-dev,bin/magento setup:di:compile,bin/magento setup:static-content:deploypara los 9 idiomas- Warm-up de caché: ejecutamos requests a páginas clave para llenar Varnish
- Atomic symlink switch:
ln -sfncambia el symlink/var/www/currental nuevo release php-fpm reloadpara que los workers carguen el nuevo código- Purge selectivo de Varnish
Si algo falla, rollback es cambiar el symlink al release anterior. Tiempo de indisponibilidad: 0 segundos.
El setup:static-content:deploy para 9 idiomas tarda ~12 minutos. Es el paso más lento del pipeline, pero como se ejecuta antes del switch, no afecta al tráfico en vivo.
SEO técnico multi-idioma
Un ecommerce con 15 tiendas y 9 idiomas es un campo minado de SEO técnico. Google necesita entender qué página es para qué país y qué idioma, sin confundir variantes.
Hreflang en todas las páginas
Cada página incluye etiquetas hreflang que apuntan a todas sus variantes:
Son 14 hreflangs por página. Con un catálogo de 60.000 productos, hablamos de 168.000 declaraciones hreflang solo para producto. Generamos esto dinámicamente con un módulo que consulta los URL rewrites de Magento por store view.
Structured data completo
Implementamos Schema.org JSON-LD en todas las páginas relevantes:
- Product: con
offers,aggregateRating,brand,sku,gtin13cuando está disponible. Google muestra rich snippets con precio y disponibilidad. - CollectionPage: en páginas de categoría, con
numberOfItemsy breadcrumb. - BreadcrumbList: navegación jerárquica completa (Home → Categoría → Subcategoría → Producto).
- Organization: datos de empresa en la home y páginas de contacto.
- FAQPage: en páginas de categoría que tienen preguntas frecuentes de producto.
Todo validado con el Rich Results Test de Google y sin errores en Search Console.
Sitemaps split por store
Un sitemap único para 15 tiendas superaría el límite de 50.000 URLs. Generamos sitemaps individuales por store view:
loviux.es/sitemap.xml→ sitemap index que apunta asitemap-products.xml,sitemap-categories.xml,sitemap-cms.xml- Mismo patrón para cada dominio (.fr, .de, .it, .nl, .pt, .pl, .co.uk, .at, .ch, .be, .com)
Cada sitemap se regenera diariamente a las 5:00 AM e incluye <lastmod> basado en la última actualización real del contenido, no la fecha de generación. Google aprecia la honestidad en los timestamps.
Integraciones clave
Brevo para email marketing
Conectamos Magento con Brevo (antes Sendinblue) para automatización de emails transaccionales y marketing:
- Sincronización de contactos bidireccional (registro, compra, abandono)
- Emails transaccionales (confirmación de pedido, envío, factura) servidos desde Brevo para mejor deliverability
- Workflows de abandono de carrito segmentados por tienda/idioma
GA4 Enhanced Ecommerce
Implementamos el tracking completo de GA4 Enhanced Ecommerce con 10 eventos estándar:
view_item, view_item_list, add_to_cart, remove_from_cart, view_cart, begin_checkout, add_shipping_info, add_payment_info, purchase y refund.
Cada evento incluye la dimensión de store view para poder segmentar rendimiento por país/idioma en los informes.
Cloudflare Turnstile
Reemplazamos reCAPTCHA por Cloudflare Turnstile en todos los formularios: registro, login, contacto, newsletter y checkout como invitado. Turnstile no muestra challenges visibles al usuario (es invisible por defecto) y tiene mejor ratio de aceptación que reCAPTCHA v3. En un ecommerce, cada fricción extra en el checkout es una venta menos.
Qué nos llevamos de este proyecto
Después de meses de desarrollo, testing y optimización, estos son los aprendizajes que más impacto tuvieron:
- Hyvä no es opcional para Magento 2 nuevo. Si empiezas un proyecto hoy con Luma, empiezas con deuda técnica. La diferencia de rendimiento es demasiado grande.
- El fallback de idioma se diseña antes de cargar el primer producto. Hacerlo después con 60.000 productos ya cargados habría sido un infierno de migraciones de datos.
- Magewire es la respuesta correcta para checkout en Hyvä. Mismo paradigma que el resto del frontend, sin dependencias extra. Laravel Livewire probó el concepto; Magewire lo lleva a Magento.
- La IA para contenido de producto no reemplaza a los copywriters, pero escala donde ellos no pueden. 81.000 textos en 9 idiomas por 420 € es una ecuación que no admite debate. La revisión humana sigue siendo necesaria para el 10-15% de edge cases.
- CSS bloqueante con Hyvä tiene más sentido que critical CSS. Cuando tu CSS total pesa menos que una imagen de avatar, la complejidad de mantener critical CSS no compensa.
- Deploy zero-downtime es obligatorio, no un nice-to-have. Con 15 tiendas y tráfico 24/7 desde múltiples zonas horarias, no hay ventana de mantenimiento segura.
Si tu empresa necesita escalar un ecommerce Magento 2, ya sea una migración a Hyvä, un setup multi-store o integraciones complejas, contacta con nuestro equipo. Llevamos más de 15 años construyendo soluciones de ecommerce que funcionan a escala real.