Skip to main content

How to Export Salesforce Data to CSV Using Lightning Aura and Apex

In plain words: Exporting data to CSV in Lightning Aura is a technique where an Apex controller fetches Salesforce records, and client-side JavaScript formats those records into comma-separated text and triggers an instant browser download—saving users time and avoiding server document storage.

Exporting Salesforce records to a standard .csv file is one of the most requested features across administrative dashboards and custom list views. Whether you are maintaining existing Aura implementations or integrating custom export workflows, combining an @AuraEnabled Apex query with client-side JavaScript file generation delivers a clean, responsive user experience.

Prerequisites

  • A Salesforce Developer Edition or Sandbox environment.
  • Basic understanding of Lightning Aura Component architecture (Component, Controller, Helper) and Apex controllers.

Step 1: Create the Server-Side Apex Controller

First, write an Apex controller that queries the records you want to export. Mark the method with @AuraEnabled(cacheable=true) for optimal performance and read access.

/* ExportDataToCSVController.cls */
public with sharing class ExportDataToCSVController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> retrieveData() {
        return [
            SELECT Id, FirstName, LastName, Email, Title, Department 
            FROM Contact 
            WITH USER_MODE 
            LIMIT 1000
        ];
    }
}

Explanation: The WITH USER_MODE clause ensures that the query adheres to the running user's Object and Field-Level Security (FLS) permissions.

Step 2: Build the Aura Component Markup

Create the component definition file (.cmp) connecting your Apex class via the controller attribute and adding a trigger button.

<!-- ExportDataToCSV.cmp -->
<aura:component controller="ExportDataToCSVController" implements="flexipage:availableForAllPageTypes">
    <lightning:card title="Data Export" iconName="utility:download">
        <div class="slds-p-around_medium">
            <p class="slds-m-bottom_small">Download contact records in CSV format:</p>
            <lightning:button 
                variant="brand" 
                label="Export to CSV" 
                iconName="utility:download" 
                onclick="{! c.exportToCSV }" />
        </div>
    </lightning:card>
</aura:component>

Step 3: Implement the Client-Side Controller

The controller handles the button click event, enqueues the server-side action, and hands the retrieved record array over to the helper.

/* ExportDataToCSVController.js */
({
    exportToCSV: function(component, event, helper) {
        var action = component.get("c.retrieveData");
        
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var records = response.getReturnValue();
                if (records && records.length > 0) {
                    var csvContent = helper.convertArrayOfObjectsToCSV(records);
                    helper.triggerDownload(csvContent, "Contact_Export.csv");
                } else {
                    console.log("No records returned to export.");
                }
            } else if (state === "ERROR") {
                var errors = response.getError();
                console.error("Error retrieving records:", errors);
            }
        });
        
        $A.enqueueAction(action);
    }
})

Step 4: Implement the Helper Functions

The helper manages data transformation, handles comma and quotation character escaping, and executes the file download using the modern Blob and URL.createObjectURL APIs.

/* ExportDataToCSVHelper.js */
({
    convertArrayOfObjectsToCSV: function(data) {
        if (!data || !data.length) {
            return null;
        }

        var columnDivider = ',';
        var lineDivider = '\r\n';

        // Extract column keys from the first record (excluding Aura metadata properties)
        var keys = Object.keys(data[0]).filter(function(key) {
            return key !== 'attributes';
        });

        var csvStringResult = '';
        csvStringResult += keys.join(columnDivider);
        csvStringResult += lineDivider;

        for (var i = 0; i < data.length; i++) {
            var rowValues = [];
            for (var j = 0; j < keys.length; j++) {
                var key = keys[j];
                var cellValue = data[i][key] !== undefined && data[i][key] !== null ? String(data[i][key]) : '';
                
                // Escape internal quotes and enclose fields containing delimiters
                if (cellValue.includes(',') || cellValue.includes('"') || cellValue.includes('\n')) {
                    cellValue = '"' + cellValue.replace(/"/g, '""') + '"';
                }
                rowValues.push(cellValue);
            }
            csvStringResult += rowValues.join(columnDivider);
            csvStringResult += lineDivider;
        }

        return csvStringResult;
    },

    triggerDownload: function(csvData, fileName) {
        // Prepend UTF-8 BOM (\uFEFF) to ensure Microsoft Excel displays special characters accurately
        var blob = new Blob(['\uFEFF' + csvData], { type: 'text/csv;charset=utf-8;' });
        var downloadUrl = URL.createObjectURL(blob);
        
        var hiddenLink = document.createElement('a');
        hiddenLink.href = downloadUrl;
        hiddenLink.download = fileName;
        hiddenLink.style.display = 'none';
        
        document.body.appendChild(hiddenLink);
        hiddenLink.click();
        document.body.removeChild(hiddenLink);
        
        URL.revokeObjectURL(downloadUrl);
    }
})
Step-by-Step Data Flow:
  • 1. Invoke Apex: Component requests sObject records asynchronously via $A.enqueueAction().
  • 2. Sanitize & Filter: Helper strips Salesforce metadata (such as the attributes key) and establishes column headers.
  • 3. Format Values: Escapes quotes and commas to maintain valid CSV syntax.
  • 4. Generate File: Packages the CSV string into a UTF-8 Blob and triggers the browser's download prompt.
Developer Warning — The attributes Object: Whenever Apex returns an sObject list to Lightning, each record includes an internal attributes object (e.g., { type: "Contact", url: "..." }). Always filter this property out during iteration, or it will render as a raw [object Object] column in your spreadsheet.
360 Card: CSV Export Architecture Summary
  • Server Responsibility: Fetch filtered data and enforce FLS via WITH USER_MODE.
  • Client Responsibility: Transform arrays to CSV string, encode characters, and prompt download.
  • Character Encoding: Prefix with \uFEFF (BOM) to preserve non-ASCII symbols in Microsoft Excel.
  • Scalability Boundary: Ideal for datasets under 2,000 records. For enterprise exports exceeding 50,000 records, migrate to batch jobs, reports, or Bulk API.
Core Takeaway: Generating CSV files client-side inside Lightning components provides instant, interactive data extraction without placing unnecessary processing load or file-storage costs on the Salesforce platform.