LWC Performance Tips – Caching, Lazy Loading

A fast Lightning Web Component feels more responsive and scales better. These performance tips focus on caching, lazy loading, and optimizing render cycles.

1. Use cacheable Apex with @wire

Mark Apex methods with @AuraEnabled(cacheable=true) so the framework can cache results.


@AuraEnabled(cacheable=true)
public static List getAccounts() {
    return [SELECT Id, Name, Industry FROM Account LIMIT 100];
}
  

2. Lazy Load Content

Only load expensive data when users need it, such as in tabs or expandable sections.


// example.js
import { LightningElement, track } from 'lwc';
import getLargeData from '@salesforce/apex/DataController.getLargeData';

export default class Example extends LightningElement {
    @track data;
    @track loaded = false;

    async handleShowDetails() {
        if (!this.loaded) {
            this.data = await getLargeData();
            this.loaded = true;
        }
    }
}
  

3. Load External Scripts and Styles Lazily


import { LightningElement } from 'lwc';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import chartJs from '@salesforce/resourceUrl/chartJs';

export default class ChartComponent extends LightningElement {
    renderedCallback() {
        if (this.chartInitialized) {
            return;
        }
        this.chartInitialized = true;

        Promise.all([
            loadScript(this, chartJs + '/chart.min.js'),
            loadStyle(this, chartJs + '/chart.css')
        ]).then(() => {
            this.initializeChart();
        });
    }
}
  

4. Minimize Re-rendering

Avoid changing properties repeatedly in quick succession and prefer getters for computed values.


get formattedName() {
    return `${this.firstName} ${this.lastName}`;
}

setFirstName(value) {
    this.firstName = value;
}

setLastName(value) {
    this.lastName = value;
}
  

5. Use trackable Patterns Sparingly

With modern LWC, only objects and arrays need @track. Simple fields are reactive by default.


// Prefer this
myCount = 0;

// Use @track only when updating nested properties
@track account = { name: '', phone: '' };
  

6. Batch DOM Queries

Query the DOM once instead of repeatedly inside loops.


renderedCallback() {
    if (this.initialized) {
        return;
    }
    this.initialized = true;

    const elements = this.template.querySelectorAll('.item');
    elements.forEach(el => {
        el.classList.add('loaded');
    });
}
  

7. Debounce User Input

Prevent too many updates by debouncing search fields and input events.


handleSearchChange(event) {
    window.clearTimeout(this.searchTimeout);
    this.searchTimeout = window.setTimeout(() => {
        this.searchTerm = event.target.value;
        this.performSearch();
    }, 300);
}
  

8. Use Conditional Rendering

Render only the UI elements needed at a given moment.


<template>
    <template if:true={showDetails}>
        <c-detail-panel data={detailData}></c-detail-panel>
    </template>
</template>
  

Key Takeaways