2 de julio de 2026

Cómo exportar archivos Excel en Laravel 13: guía completa con Laravel Excel

Foto de Marco Orta Marco Orta | 6 min de lectura
Compartir
Datos de una base de datos Laravel siendo exportados a una hoja de cálculo Excel
Tabla de Contenidos

    Generar un Excel descargable es uno de los requisitos más habituales en cualquier panel de administración: exportar el listado de pedidos, un reporte de ventas o la base de clientes para que el equipo lo abra en su hoja de cálculo. En Laravel, el estándar sigue siendo el paquete maatwebsite/excel (versión 3.1.69 a abril de 2026), el mismo que usamos para importar archivos Excel.

    En esta guía actualizada para Laravel 13 vas a ver cómo crear una clase de exportación, añadir encabezados y estilos, controlar el formato de las celdas, exportar a distintos formatos (XLSX, CSV) y, lo más importante para producción, mover exportaciones pesadas a cola para no reventar la memoria del servidor.

    1. Tener Laravel 13 instalado

    Si todavía no tienes el proyecto listo, revisa la guía dedicada: Cómo instalar Laravel 13. Recuerda que Laravel 13 requiere PHP 8.3 como mínimo (8.4 en la práctica desde Laravel 13.3).

    2. Instalación del paquete maatwebsite/excel

    Instala el paquete vía Composer:

    composer require maatwebsite/excel
    

    El paquete registra automáticamente su service provider y el facade Excel. Si quieres ajustar la configuración por defecto (formato de fechas, disco de almacenamiento, etc.), publica el archivo de config:

    php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config
    

    Esto crea config/excel.php, donde puedes tocar cosas como el csv delimiter o el disco por defecto.

    ¿maatwebsite/excel es compatible con Laravel 13?

    Sí. No hay una “versión para Laravel 13” del paquete: la misma rama 3.1 de siempre lo soporta. Desde la 3.1.69 (abril de 2026) declara compatibilidad con illuminate/support hasta la 13.x, así que en un proyecto Laravel 13 el composer require anterior instala sin fricción. Si estás subiendo desde Laravel 12, tus clases de exportación siguen funcionando tal cual (la API no cambió); solo actualiza con composer update maatwebsite/excel --with-all-dependencies, y ante cualquier conflicto usa composer why-not laravel/framework 13.0 para ver qué paquete estorba.

    3. Creación de la clase de exportación

    Toda la lógica de exportación vive en una clase dedicada dentro de app/Exports. Genérala con Artisan asociándola a un modelo:

    php artisan make:export PedidosExport --model=Pedido
    

    Esto crea app/Exports/PedidosExport.php con una clase que implementa el concern FromCollection:

    <?php
    
    namespace App\Exports;
    
    use App\Models\Pedido;
    use Maatwebsite\Excel\Concerns\FromCollection;
    
    class PedidosExport implements FromCollection
    {
        public function collection()
        {
            return Pedido::all();
        }
    }
    

    El método collection() devuelve los datos que se volcarán en el archivo. Ya con esto tienes un Excel funcional, pero le faltan encabezados y formato — lo vamos a mejorar con los concerns de las siguientes secciones.

    4. Las fuentes de datos: FromCollection, FromQuery, FromView

    maatwebsite/excel te deja elegir de dónde salen los datos según el caso. Estas son las cuatro opciones principales:

    • FromCollection — devuelves una colección de Eloquent o un array. Sencillo, pero carga todo en memoria. Ideal para volúmenes pequeños.
    • FromQuery — devuelves una query sin ejecutar y el paquete la procesa en chunks automáticamente. La opción recomendada para tablas grandes.
    • FromView — renderizas una vista Blade con una <table> HTML. Perfecto cuando necesitas control total del layout o estilos con HTML.
    • FromArray — para datos que ya tienes en un array plano.

    Ejemplo con FromQuery, mucho más eficiente en memoria:

    <?php
    
    namespace App\Exports;
    
    use App\Models\Pedido;
    use Maatwebsite\Excel\Concerns\FromQuery;
    use Maatwebsite\Excel\Concerns\Exportable;
    
    class PedidosExport implements FromQuery
    {
        use Exportable;
    
        public function query()
        {
            return Pedido::query()->where('estado', 'completado');
        }
    }
    

    5. Encabezados y mapeo de columnas

    Un Excel sin encabezados no sirve de mucho. Añade el concern WithHeadings para la fila de títulos y WithMapping para decidir exactamente qué columnas y en qué formato se exporta cada fila:

    <?php
    
    namespace App\Exports;
    
    use App\Models\Pedido;
    use Maatwebsite\Excel\Concerns\FromQuery;
    use Maatwebsite\Excel\Concerns\WithHeadings;
    use Maatwebsite\Excel\Concerns\WithMapping;
    
    class PedidosExport implements FromQuery, WithHeadings, WithMapping
    {
        public function query()
        {
            return Pedido::query()->with('cliente');
        }
    
        public function headings(): array
        {
            return ['ID', 'Cliente', 'Total', 'Estado', 'Fecha'];
        }
    
        public function map($pedido): array
        {
            return [
                $pedido->id,
                $pedido->cliente->nombre,
                number_format($pedido->total, 2),
                ucfirst($pedido->estado),
                $pedido->created_at->format('d/m/Y'),
            ];
        }
    }
    

    Fíjate en el with('cliente'): cargar la relación por adelantado evita el problema N+1 cuando exportas miles de filas. El método map() es también el sitio ideal para formatear fechas y montos como los quiere ver el usuario final.

    6. Estilos y formato de celdas

    Para que el reporte se vea profesional, aplica ancho automático, negrita en los encabezados y formato numérico correcto:

    use Maatwebsite\Excel\Concerns\ShouldAutoSize;
    use Maatwebsite\Excel\Concerns\WithStyles;
    use Maatwebsite\Excel\Concerns\WithColumnFormatting;
    use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
    use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
    
    class PedidosExport implements FromQuery, WithHeadings, WithMapping, ShouldAutoSize, WithStyles, WithColumnFormatting
    {
        // ...query(), headings() y map() como antes...
    
        public function styles(Worksheet $sheet)
        {
            return [
                1 => ['font' => ['bold' => true]], // encabezados en negrita
            ];
        }
    
        public function columnFormats(): array
        {
            return [
                'C' => NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1, // columna Total
            ];
        }
    }
    
    • ShouldAutoSize ajusta el ancho de las columnas al contenido.
    • WithStyles te da acceso al objeto Worksheet de PhpSpreadsheet para estilos avanzados (colores, bordes, alineación).
    • WithColumnFormatting aplica formatos de número, moneda o fecha por columna.

    Archivo pedidos.xlsx abierto en una hoja de cálculo con encabezados en negrita, columna de totales con formato de moneda y anchos ajustados

    Así queda el archivo: encabezados en negrita, columna C con formato de moneda y anchos automáticos — todo declarado en la clase de exportación

    7. Descargar y almacenar el archivo

    Con la clase lista, dispararla desde un controlador es trivial. El facade Excel ofrece dos operaciones principales:

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Exports\PedidosExport;
    use Maatwebsite\Excel\Facades\Excel;
    
    class PedidoController extends Controller
    {
        // Descarga directa al navegador
        public function export()
        {
            return Excel::download(new PedidosExport, 'pedidos.xlsx');
        }
    
        // Guardar en un disco de Laravel (local, s3, etc.)
        public function store()
        {
            Excel::store(new PedidosExport, 'reportes/pedidos.xlsx', 's3');
    
            return back()->with('status', 'Reporte generado');
        }
    }
    

    Y la ruta correspondiente:

    use App\Http\Controllers\PedidoController;
    
    Route::get('/pedidos/export', [PedidoController::class, 'export'])->name('pedidos.export');
    

    Excel::download() fuerza la descarga en el navegador; Excel::store() escribe el archivo en cualquier disco configurado en config/filesystems.php — útil para reportes programados o para enviarlos por email después.

    8. Exportar a diferentes formatos (XLSX, CSV)

    El mismo export sirve para varios formatos: solo indica la extensión y el tipo de escritor como tercer argumento:

    use Maatwebsite\Excel\Excel as ExcelWriter;
    
    // CSV
    Excel::download(new PedidosExport, 'pedidos.csv', ExcelWriter::CSV);
    
    // XLSX (por defecto si no indicas nada)
    Excel::download(new PedidosExport, 'pedidos.xlsx', ExcelWriter::XLSX);
    

    Si lo que necesitas es una conversión rápida de datos JSON a CSV sin montar todo un export en Laravel, puedes usar mi conversor de JSON a CSV para pruebas puntuales.

    9. Exportaciones grandes: procesamiento en cola

    Aquí está la diferencia entre un tutorial y código de producción. Exportar 100 mil filas de forma síncrona agota la memoria y da timeout. La solución es doble: usar FromQuery (que ya procesa en chunks) e implementar ShouldQueue para mover el trabajo a un worker en segundo plano.

    use Maatwebsite\Excel\Concerns\FromQuery;
    use Maatwebsite\Excel\Concerns\WithHeadings;
    use Illuminate\Contracts\Queue\ShouldQueue;
    
    class PedidosExport implements FromQuery, WithHeadings, ShouldQueue
    {
        // ...
    }
    

    Y lo lanzas a la cola con queue():

    public function export()
    {
        (new PedidosExport)->queue('reportes/pedidos.xlsx', 's3');
    
        return back()->with('status', 'El reporte se está generando; te avisaremos cuando esté listo.');
    }
    

    El paquete divide la exportación en jobs que se procesan de forma independiente, manteniendo el uso de memoria bajo control. Combínalo con colas de Laravel sobre Redis y notifica al usuario por email o broadcasting cuando el archivo esté listo en el disco.

    10. Múltiples hojas en un mismo archivo

    Para reportes complejos —por ejemplo, una hoja por mes o por sucursal— implementa WithMultipleSheets:

    use Maatwebsite\Excel\Concerns\WithMultipleSheets;
    
    class ReporteAnualExport implements WithMultipleSheets
    {
        public function sheets(): array
        {
            $sheets = [];
    
            foreach (range(1, 12) as $mes) {
                $sheets[] = new PedidosPorMesSheet($mes);
            }
    
            return $sheets;
        }
    }
    

    Cada elemento del array es a su vez una clase de exportación (que puede implementar WithTitle para nombrar la pestaña). Así generas un único .xlsx con doce hojas de un solo download().

    Conclusión

    Exportar a Excel en Laravel 13 es directo con maatwebsite/excel: creas una clase de exportación, eliges la fuente de datos adecuada (FromQuery para volúmenes grandes), añades encabezados y estilos con los concerns, y disparas la descarga desde el controlador. La clave para producción es no exportar nunca de forma síncrona datasets grandes: FromQuery + ShouldQueue mantiene tu app estable con cualquier volumen.

    Para seguir construyendo tu panel de administración:

    Compartir

    Buscar

    Etiquetas

    Laravel PHP Tutorial IA JavaScript Desarrollo Web Buenas Prácticas Laravel 13 Seguridad Migración Herramientas Claude SEO Expresiones Regulares Manipulación de Texto