Excel Export using laravel with vuejs

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Data Exports: Solving the Laravel/Vue.js Download Paradox

As a senior developer, I frequently encounter scenarios where backend logic appears correct, but the frontend interaction fails to deliver the expected result. The issue you are facing—where a standard request downloads a file successfully, but an Axios request from Vue.js returns a success message instead of the actual Excel file—is a classic symptom of a misunderstanding in how HTTP responses and file streaming are handled in an API context.

This post will dive deep into why this happens when exporting data using Laravel's Excel functionality and provide the robust solution to ensure your Vue.js application can reliably trigger file downloads via API calls. We’ll explore the mechanics behind this behavior and implement the best practices for seamless data delivery.

Understanding the Export Mechanism in Laravel

You are correctly using Laravel's built-in package (likely Maatwebsite/Laravel-Excel) to handle the export. The method Excel::download() is designed to initiate a file download directly to the browser when accessed via a standard route, as it forces the browser to treat the response as a file stream.

When you use an API endpoint (like /api/export) and return a simple JSON object (e.g., {"success": true}), the browser receives a standard JSON payload. It does not interpret this data as a file stream, which is why it doesn't initiate a download, even if the backend successfully generated the Excel file on the server.

The Diagnosis: Why Axios Fails Where Requests Succeed

The difference lies entirely in the HTTP response headers and body content sent back to the client.

  1. Direct Request (Success): When a browser navigates directly to a route that returns an Excel::download() result, Laravel correctly sets the necessary headers (Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet and Content-Disposition) telling the browser to download the file immediately.
  2. Axios Request (Failure): When your Vue.js code uses Axios to hit an endpoint, if that endpoint returns a standard JSON response like { "success": true }, the browser simply displays that JSON data in the console or as a successful API call, not triggering a file download.

To fix this for API-driven exports, we need to stop returning JSON and start returning the actual file content stream with the correct HTTP headers.

The Solution: Streaming Files via API

Instead of just calling Excel::download(), you need to manually handle the response stream in your controller method. This involves using Laravel's response methods to force the browser to treat the output as a downloadable file.

Here is how we adjust the process in your controller:

Step 1: Modify the Controller Logic (The Fix)

Instead of relying solely on Excel::download() within an API context, you need to stream the generated file directly into the response. This requires using the Response facade and ensuring the correct headers are set.

In your export controller method, adapt it to return a downloadable response:

use Illuminate\Support\Facades\Response;
use Maatwebsite\Excel\Facades\Excel;
use App\Exports\StudentExport; // Assuming this is your export class

public function export()
{
    // 1. Create the file stream using the Excel facade
    $file = Excel::download(new StudentExport, 'users.xlsx');

    // 2. Return the response directly with the correct headers
    return Response::download($file, 'users.xlsx');
}

Note: In a pure API context where you must return data (not force a redirect), streaming the file content requires slightly different handling depending on whether you are returning a raw stream or a wrapper response. For direct downloads triggered by an API call, using Response::download() is often the most straightforward approach as it handles all necessary headers automatically.

Step 2: Update the Vue.js Request

Since the controller is now correctly streaming the file download, your Axios call remains clean and successful. The success message should appear after the download has been initiated by the browser.

axios.get('api/export')
    .then(() => {
        // This block executes successfully once the server initiates the file stream
        toast({
            type: 'success',
            title: 'Export process initiated. Check your downloads!'
        });
    })
    .catch((error) => {
        // Handle actual server errors (e.g., 500 errors)
        toast({
            type: 'warning',
            title: 'Export failed. Please try again.'
        });
    });

Conclusion: Best Practices for API Exports

The core lesson here is that API endpoints serve data, not file streams directly. When you want to trigger a browser download via an API call, the endpoint must be configured specifically to output the raw binary file content with appropriate HTTP headers.

By ensuring your Laravel controller uses methods designed for streaming responses (like Response::download()) instead of just returning JSON, you bridge the gap between server-side file generation and client-side download initiation perfectly. For more complex scenarios involving custom PDF or CSV generation, exploring service layers within frameworks like Laravel is highly recommended for maintaining clean, scalable code.