How to Query and Display Files Efficiently Using Lightning Web Components (LWC) in Salesforce

Managing and displaying files effectively is essential for creating a dynamic and user-friendly experience in Salesforce. With the introduction of Lightning Web Components (LWC), developers now have a powerful toolkit to build fast, scalable, and modern Salesforce applications. When it comes to handling files — such as attachments, documents, or Salesforce Files — it’s important to understand how to query these efficiently and display them with performance and usability in mind.

In this article, we’ll walk through how to efficiently query and display files in Salesforce using LWCs. We’ll examine the data model behind files in Salesforce, use Apex classes to retrieve related content, and implement LWCs to render files in a seamless interface.

Understanding the Salesforce Files Data Model

Before you start writing code, it’s important to understand how Salesforce manages files. Files in Salesforce are not stored directly on records like in the legacy Notes & Attachments system. Instead, Salesforce Files uses a powerful content management model that allows a file to be associated with multiple records using link objects.

Here are the core objects you’ll be working with when querying files:

  • ContentVersion: Represents a specific version of a file. This is where the actual content (title, file type, version number) resides.
  • ContentDocument: A container for related file versions. This is the object that stays constant even as versions change.
  • ContentDocumentLink: The junction object that connects a ContentDocument to one or more records.

With this in mind, your goal when querying files related to a specific Salesforce record becomes clearer: Use the ContentDocumentLink to get the ContentDocumentId and then use that to access the latest ContentVersion.

Querying Files Using Apex

To access files related to a record (for example, an Opportunity or Account), you’ll need to write an Apex class that performs the necessary SOQL query. Here’s a code snippet showing how to query files attached to a record:


public with sharing class FileController {
    @AuraEnabled(cacheable=true)
    public static List<ContentVersion> fetchFiles(Id recordId) {
        List<ContentDocumentLink> links = [
            SELECT ContentDocumentId 
            FROM ContentDocumentLink 
            WHERE LinkedEntityId = :recordId
        ];
        
        Set<Id> docIds = new Set<Id>();
        for(ContentDocumentLink link : links) {
            docIds.add(link.ContentDocumentId);
        }
        
        return [
            SELECT Id, Title, FileExtension, ContentDocumentId, VersionData
            FROM ContentVersion
            WHERE ContentDocumentId IN :docIds
            AND IsLatest = TRUE
        ];
    }
}

This retrieves the latest version of all files linked to a given record. Note the use of the @AuraEnabled(cacheable=true) annotation, which helps improve performance by allowing LWCs to cache results.

Creating the LWC to Display Files

Once the data is retrieved in Apex, the next step is to display it using a Lightning Web Component. Let’s outline the architecture first:

  • Call the Apex method from your LWC using @wire.
  • Parse the file data and render it in a repeater (e.g., using <template for:each>).
  • Add download capabilities for each file.

Here’s how your LWC JavaScript might look:


import { LightningElement, wire, api } from 'lwc';
import fetchFiles from '@salesforce/apex/FileController.fetchFiles';

export default class RelatedFilesViewer extends LightningElement {
    @api recordId;
    files = [];
    error;

    @wire(fetchFiles, { recordId: '$recordId' })
    wiredFiles({ error, data }) {
        if (data) {
            this.files = data.map(file => ({
                ...file,
                downloadUrl: `/sfc/servlet.shepherd/version/download/${file.Id}`
            }));
        } else if (error) {
            this.error = error;
        }
    }
}

And the HTML template that accompanies it:


<template>
    <template if:true={files}>
        <ul>
            <template for:each={files} for:item="file">
                <li key={file.Id}>
                    {file.Title}.{file.FileExtension}
                    <a href={file.downloadUrl} target="_blank">Download</a>
                </li>
            </template>
        </ul>
    </template>

    <template if:true={error}>
        <p>Error loading files: {error.message}</p>
    </template>
</template>

The result is a smooth, responsive display of all files related to your record, with direct download links.

Performance Considerations and Best Practices

When working with file queries in LWC, performance is key. Here are some best practices to ensure an optimal user experience:

  • Use cacheable methods: Mark your Apex method with cacheable=true if the data can be safely cached. This reduces unnecessary server trips.
  • Limit the number of results: Implement pagination, lazy loading, or limits (e.g. LIMIT 10) to avoid loading hundreds of records at once.
  • Minimize fields retrieved: Only query the specific fields you need to minimize payload size.
  • Secure file access: Ensure users only see files they have access to using standard Salesforce sharing and permission models.

Additionally, remember that downloading files via VersionData URLs bypasses some native file viewing options. You can customize the experience further by embedding file previews via lightning:fileCard or lightning:fileUpload components, if needed.

Enhancing User Experience

If your app involves frequent user interaction with files, consider improving the UI with these elements:

  • File icons: Display an icon next to each file based on extension (PDF, DOCX, etc.).
  • Previews: Use Salesforce’s file preview URLs with a modal or inline viewer to preview PDFs or images.
  • Upload support: Add file upload capability with tools like <lightning-file-upload> to let users add files directly from the same component.
  • Error messages: Provide clear feedback on load failures, missing files, and invalid file types.

With these enhancements, your users will enjoy a much richer experience while interacting with files within Salesforce records.

Deploying and Testing Your LWC

Once you’ve built and styled your component, deploy it using your preferred method — via SFDX, VS Code, or directly in the Salesforce UI. Make sure to test it across record types, users, and profile levels to ensure compatibility and security.

Here are several testing tips:

  • Test on records with no files: Ensure the component gracefully handles empty results.
  • Test as different users: Use the standard “Login As” or permission sets to simulate user roles and access.
  • Test across browsers: LWC components are modern and compatible, but check display in Chrome, Firefox, and Edge if needed.
  • Inspect response times: Use Chrome DevTools to measure API response times for file queries.

Conclusion

Efficiently handling files in Salesforce is essential for many business scenarios, from sales and service to HR and legal. Leveraging Lightning Web Components with Apex for backend data and dynamic front-end rendering allows you to build blazing fast, deeply integrated file components for any record in Salesforce.

By understanding the Salesforce file data model, writing optimized Apex queries, and building interactive LWC screens, you can transform the way users interact with content — all within the familiar Salesforce environment.

Whether you’re building a custom Opportunity file viewer or integrating files with your Client Management System, this approach ensures modern, performant, and maintainable code — just the way Salesforce development was meant to be.

I'm Ava Taylor, a freelance web designer and blogger. Discussing web design trends, CSS tricks, and front-end development is my passion.
Back To Top