[object Object]

If your record page EPT is over two seconds at the 75th percentile, your reps are tab-switching to their inbox before your data loads. You are not measuring trust, you are measuring patience.

A performance budget is not a goal. It is a refusal to ship past a number.

The numbers that matter

Set these for every record page in your org:

  • EPT P75 < 2.0s — Experienced Page Time, what the user actually feels.
  • Initial bytes < 800 KB — total JS + JSON shipped before first interaction.
  • Component count < 25 — components on the default tab.
  • LDS calls < 10 — Lightning Data Service getRecord invocations at load.
  • Server calls < 5Apex / API roundtrips before the page is interactive.

Anything above these and you owe yourself a refactor.

How to measure honestly

Salesforce gives you three tools. Use them in this order.

  1. Lightning Usage App for trend data. Aggregate, lagging, but free.
  2. Page Performance tab in Setup for component-level cost. Run on a primed cache and a cold cache.
  3. Browser DevTools with ?eptVisualizer=1 query param for the truth.

The trap: developer orgs are 3x faster than production because of seat count. Always measure in a sandbox sized like prod, with a user profile sized like a real rep.

Component cost: what actually burns budget

In our last twenty audits, the same five suspects:

  • Related lists with formula fields that span objects. Each row evaluates the formula client-side.
  • Custom LWCs that wire to multiple Apex methods at connectedCallback. Three @wire on connection = three serial roundtrips.
  • Embedded reports with no row limit. The page waits for the report to render before declaring interactive.
  • Flow components that auto-launch. They block the EPT timer until their first screen renders.
  • Path components on objects with 15+ statuses. The path renders all stages eagerly.

Pattern: defer everything below the fold

Use the lazyLoad attribute on Lightning App Builder components and split your record page into “above the fold” and “below the fold” zones.

// myComponent.js
import { LightningElement, api } from 'lwc';

export default class MyComponent extends LightningElement {
  @api recordId;
  isVisible = false;

  connectedCallback() {
    // Don't fire @wire on mount. Wait for intersection.
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        this.isVisible = true;
        observer.disconnect();
      }
    });
    // Defer observer attachment until the host is in the DOM.
    queueMicrotask(() => observer.observe(this.template.host));
  }
}
<!-- myComponent.html -->
<template>
  <template lwc:if={isVisible}>
    <c-expensive-related-list record-id={recordId}></c-expensive-related-list>
  </template>
</template>

This single pattern removed 600ms from a Service Cloud case page in a recent engagement.

Pattern: collapse @wire fan-out

If you have three components each doing @wire(getRecord, ...) for the same record, you have three roundtrips. Lightning Data Service deduplicates within a request, but only if the field selection matches exactly.

Centralize the wire in one parent and pass the record down as a property:

import { LightningElement, api, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';

const FIELDS = [
  'Account.Name',
  'Account.AnnualRevenue',
  'Account.Industry',
  'Account.Owner.Name'
];

export default class AccountSummary extends LightningElement {
  @api recordId;
  record;

  @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
  wiredRecord({ data, error }) {
    if (data) this.record = data;
  }
}

The “Dynamic Forms tax”

Dynamic Forms are great for UX and bad for default-tab budgets when overused. Each visibility-rule expression evaluates client-side on every field change. A page with 60 dynamically-shown fields and 20 visibility rules can blow 400ms just on rule evaluation. See the Dynamic Forms best practices piece for the rule-cardinality rules.

Enforcing the budget in CI

The Salesforce CLI now exposes a performance scan in pipelines:

sf lightning analyze page-performance \
  --target-org ci-sandbox \
  --record-types Account,Opportunity,Case \
  --max-ept 2000 \
  --max-bytes 800000 \
  --fail-on-regression \
  --output-format json > perf-report.json

Wire that into your deploy pipeline. A regression > 200ms on any tracked page fails the build. Stop trusting humans to notice.

UX note for Service Cloud

On case pages, the highest-impact change is moving the case feed to a lazy-loaded tab. The feed is heavy and rarely needed on first load — agents triage from related cases and recent activity first. EPT savings of 800ms+ are common.

Bottom line

  • Pick a budget — EPT P75 < 2.0s, < 800 KB initial, < 25 components, < 10 LDS, < 5 server calls.
  • Measure on prod-sized sandboxes with prod-shaped profiles.
  • Lazy load anything below the fold; collapse @wire fan-out; throttle Dynamic Forms rule count.
  • Enforce in CI with sf lightning analyze page-performance and fail builds on regression.
  • The biggest wins are almost always related lists and embedded reports — start there.
[object Object]
Share