{"id":193201,"date":"2020-02-11T11:00:22","date_gmt":"2020-02-11T18:00:22","guid":{"rendered":"http:\/\/developer.salesforce.com\/blogs\/?p=193201"},"modified":"2025-11-05T02:20:59","modified_gmt":"2025-11-05T09:20:59","slug":"designing-lightning-pages-for-scale","status":"publish","type":"post","link":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale","title":{"rendered":"Designing Lightning Pages for Scale"},"content":{"rendered":"<p>This blog post provides guidance to architects, developers, and administrators in creating and designing Lightning pages that scale and perform well. Where we used to have Visualforce and multi-page applications, we now have Lightning Web Components (LWC) and single-page applications (SPA).<\/p>\n<p>With SPA,<b> <\/b>a user can do most of the work from the same page without navigating to other pages. This is a huge productivity gain and can result in a great user experience; however, proper design is recommended to ensure large volumes of requests do not pose any scale or performance challenges.<\/p>\n<p>SPAs are made up of components that receive and send data to the server using XML HTTP Requests (XHR).<br \/>\nWhen a page loads, components can be rendered in parallel, making multiple XHRs to the server in order to retrieve data and metadata.<\/p>\n<p>In implementations with a large user base using the Lightning application concurrently, the component architecture can create a great number of network requests in the Org. Proper design is recommended to ensure large volumes of requests do not pose any scale or performance challenges.<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone wp-image-193203 size-full\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210144743\/components-e1581371286487.png\" class=\"postimages\" width=\"700\" height=\"297\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p>&nbsp;<\/p>\n<h2>A Word about Scale and Performance<\/h2>\n<p>Scaling is the ability of a system to perform consistently under load. Lack of ability to scale can impact all processes in a system and can impact business growth. Performance<b> <\/b>is the time taken for a request to complete. Your user<b> <\/b>experience can be negatively impacted by UI applications that don\u2019t perform well.<\/p>\n<h3>Factors that Impact Lightning scale<\/h3>\n<p>In implementations with a large user base, there are certain aspects of page design that can be optimized to scale. A few are summarized here:<\/p>\n<ol>\n<li>Number of visible components on page load<\/li>\n<li>Custom list views with lots of data<\/li>\n<li>Related Lists, Quick Links<\/li>\n<li>Custom Components<\/li>\n<li>APEX &amp; backend<\/li>\n<li>UI Forms<\/li>\n<\/ol>\n<p>Below you will find recommendations for each of these page design ideas.<\/p>\n<p>Number of components on a page<\/p>\n<p>Based on an analysis of various customer implementations, we\u2019ve found that Lightning pages with the right amount of components load faster, and Lightning implementation scales well overall. So how do we determine the right number of components?<\/p>\n<p>&nbsp;<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone wp-image-193213 size-full\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210164330\/visible-components-e1581378233595.png\" class=\"postimages\" width=\"700\" height=\"302\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<h3>Solution 1: Lazy Loading Tabs<\/h3>\n<p>Showing actionable components as visible components is both efficient and can result in a better user experience when implemented correctly. This is called lazy loading: wherein components are shown only on demand or progressively as the user navigates through a task. One lazy loading technique is to use tabs and nest components under tabs. Components nested in tabs do not execute any XHRs and are not part of the DOM.<\/p>\n<h3>Solution 2: Lazy Loading With Personas<\/h3>\n<p>Another way to load components efficiently is to group components based on user persona rather than functionality. This way only higher priority components needed by a user to complete a certain tasks are visible on page load.<\/p>\n<p>In the example below, we see components relevant for an insurance agent. Products are what the agent wants to access quickly. Components that are secondary to a user\u2019s needs, such as claims, details, and reports &#8211; can be in tabs.<\/p>\n<p>&nbsp;<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193214\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210164703\/visible-e1581378449157.png\" class=\"postimages\" width=\"652\" height=\"413\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p>&nbsp;<\/p>\n<h2>Lazy Loading in Custom Components<\/h2>\n<p>LWC provides an easy way to do lazy loading with the <code>if:true<\/code><b> <\/b>directive<b>.<\/b><\/p>\n<p>In the code below, ensure the property <code>showForm<\/code><i> <\/i>is false, <code>c:formcompoment<\/code> and all its HTML elements are not part of the DOM. <code>c:formcompoment<\/code> is a custom component stub we are using for this example. This reduces the number of DOM elements, which improves page load time, and avoids XHRs to the server, allowing for scale.<\/p>\n<p><b>TIP: <\/b><i>showForm<\/i> variable in Javascript can be switched between true or false with a button click.<\/p>\n<p>Lightning Web Component<\/p>\n<pre>&lt;template if:true={showForm}&gt;\r\n    &lt;c:formcomponent&gt; - \/\/component is not visible unless showForm == true\r\n&lt;\/template&gt;<\/pre>\n<p>Aura component<\/p>\n<pre>&lt;aura:if isTrue=\"{!v.showForm}\"&gt;\r\n    &lt;c:formcomponent&gt; - \/\/component is not visible unless showForm == true\r\n&lt;\/aura:if&gt;<\/pre>\n<h2>Long custom list views<\/h2>\n<p>Custom lists with a large number of rows can be a performance and scale issue. Based on our analysis, a list of 2000 rows takes approximately 10 seconds to render. Much of the time is spent in the browser because Javascript takes time to iterate each row item and render.<\/p>\n<p>The list shown here has 2000 rows. Using browser tools to measure<b> <\/b>list rendering time we see that about 9 seconds are spent on Javascript and 1 second on browser-style recalculations.<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193215\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210165105\/oppor-e1581378689766.png\" class=\"postimages\" width=\"700\" height=\"232\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193216\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210165109\/9secs-e1581378736323.png\" class=\"postimages\" width=\"700\" height=\"92\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p><i><strong>NOTE:<\/strong> This is a sample. Time taken is subject to list types and other factors.<\/i><\/p>\n<p>Nine seconds is too long for most users, so here are a few effective solutions to reduce time to perform.<\/p>\n<h3>Solution 1: Custom Lists<\/h3>\n<p>We can use LWC for custom Lists. Javascript processing is faster in LWC, so iterating the list items will be faster. LWC provides ListUI module to import standard listviews. For custom listviews, pagination is highly recommended.<\/p>\n<h3>Solution 2: Pagination<\/h3>\n<p>Paginate the list data on the server and on the client. Pagination shows less data at a time, making for a better user experience. With pagination, a small number of list rows can be rendered on the client side. Based on the analysis, lists with 50 or fewer rows render quickly, resulting in a better user experience.<\/p>\n<p>Below is sample code demonstrating pagination in Javascript for a custom listview in LWC.<\/p>\n<p>&nbsp;<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193220\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211100824\/DIckenson-2-e1581440915690.png\" class=\"postimages\" width=\"700\" height=\"130\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p>Below is sample Javascript code for implementing pagination in a custom list.<\/p>\n<pre>&lt;pre&gt;\r\nimport { LightningElement, track, wire, api } from \"lwc\";\r\nmport getContacts from \"@salesforce\/apex\/ListViewPlusDataController.getContacts\";\r\nimport { getObjectInfo } from \"lightning\/uiObjectInfoApi\";\r\nimport CONTACT_OBJECT from \"@salesforce\/schema\/Contact\";\r\nexport default class Listviewplus extends LightningElement {\r\n.....\r\n@wire(getContacts)\r\n  wiredContacts({ error, data }) {    \r\n    \r\n    if (error) {\r\n      this.error = error;\r\n    } else if (data) {\r\n      this.contactsbackup = data;\r\n      this.contacts = data.slice(1, 50); \r\n    }\r\n .....\r\n @api\r\n  pressRight(left, right) {\r\n    this.contacts = this.contactsbackup.slice(left, right);\r\n  }\r\n @api\r\n  pressLeft(left, right) {\r\n    this.contacts = this.contactsbackup.slice(left, right);\r\n  }\r\n  &lt;pre&gt;<\/pre>\n<p>Pagination can be as simple as using buttons to move through the list as shown here.<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193222\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211101134\/50-of-2000-e1581441103219.png\" class=\"postimages\" width=\"514\" height=\"110\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<br \/>\nSample HTML code to render the list controls.<\/p>\n<pre> &lt;div class=\"reccount slds-col slds-size_1-of-12\"&gt;\r\n   &lt;h6 class=\"slds-small-size slds-section__title\" &gt;\r\n            {leftIndex} - {rightIndex} of {numrecords}&lt;\/h6&gt;\r\n &lt;\/div&gt;\r\n &lt;div class=\"leftarrow slds-col slds-size_1-of-12\"&gt;\r\n    &lt;lightning-button-icon title=\"Go To Previous Page Of This List\" \r\n        icon-name=\"utility:left\"  size=\"large\" alternative-text=\"refresh this view\" \r\n        onclick={pressLeft} disabled={leftDisabled}&gt;&lt;\/lightning-button-icon&gt;\r\n &lt;\/div&gt;\r\n \r\n &lt;div class=\"rightarrow slds-col slds-size_1-of-12\"&gt;\r\n       &lt;lightning-button-Icon title=\"Go To Next Page Of This List\" \r\n       icon-name=\"utility:right\"  size=\"large\" \r\n       alternative-text=\"refresh this view\" \r\n       onclick={pressRight} disabled={rightDisabled}&gt;&lt;\/lightning-button-Icon&gt;\r\n &lt;\/div&gt;<\/pre>\n<h2>Optimizing Quick Links<\/h2>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193223\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211101235\/quick-links-e1581441167880.png\" class=\"postimages\" width=\"700\" height=\"93\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p>Quick links are great, they make it easy to access related data quickly. Quick links show counts of records for related objects and show a partial list on mouse hover.<\/p>\n<p>In implementations with a large number of concurrent users, it is advisable to configure quick links into a tab. <b> <\/b>This prevents retrieving object record counts as well as accidental hovering on the quick links and thereby avoiding XHRs<b> <\/b>back to the server<b>.<\/b><\/p>\n<p>Let us look at how much page load time is saved by moving the Related quick links to its own tab.<\/p>\n<h3>Measuring the benefits<\/h3>\n<p>We did a simple test to measure the impact of page design on page performance. This test was conducted on a page containing 8 components, including the Related List quick links component (more details on that below).<\/p>\n<table>\n<tbody>\n<tr>\n<th>A<\/th>\n<th>Quick Links on the main page<\/th>\n<th>Quick links in a tab<\/th>\n<th>Improvement<\/th>\n<\/tr>\n<\/tbody>\n<colgroup>\n<col \/>\n<col \/>\n<col \/>\n<col \/><\/colgroup>\n<tbody>\n<tr>\n<td>Page Load Time (seconds)<\/td>\n<td>2.6<\/td>\n<td>2.2<\/td>\n<td>0.4<\/td>\n<\/tr>\n<tr>\n<td>Number Of XHRs on page load<\/td>\n<td>42<\/td>\n<td>35<\/td>\n<td>7<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We re-configured the page by moving the Related List quick links into its own tab<b>,<\/b> which resulted in a 0.4 second improvement. This is a direct result of a reduced number of XHR calls made during page load, as the Related List quick links component does not get rendered.<\/p>\n<p><em><strong>NOTE:<\/strong> This data is from basic tests relevant only for this post. Results will vary based on different factors.<\/em><\/p>\n<h2>Creating Custom Components that Scale<\/h2>\n<p>Custom components are useful for creating customized business applications that leverage the power of the Salesforce platform.<\/p>\n<p>LWC is a great framework for creating new custom components. Apart from the scale and performance benefits, development is made much easier with our provided <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.lightning.meta\/lightning\/lightning_overview.htm\">Lightning Web Component Base Components<\/a>, such as <code>listView<\/code>, <code>recordForm<\/code>, and more.<\/p>\n<p>These highly-optimized components help your clients retrieve data without complex backend code. For more complex business transactions, LWC can always use Apex<b>.<\/b><\/p>\n<h2>Using Platform Cache<\/h2>\n<p>For custom components that have to be visible on page load try using platform cache in Apex.<b> <\/b>Platform cache provides simple API for retrieval and insertion into cache. Requests from custom components are retrieved from the cache, avoiding SOQL queries and database connection setup.<\/p>\n<p>Cache retrieval is usually less than<b> <\/b>10ms,<b> <\/b>improving component render time and protecting database resources from being impacted when a large number of users load their pages with custom components. Let\u2019s look at some sample Platform cache code in Apex:<\/p>\n<pre>public static String getOffers(String agentId) {\r\n        String cacheOffer = (String)Cache.Org.get(agentId); \r\n\r\n\/\/Cast to String since we serialized the value.\r\n        if (cacheOffer != null) {\r\n             return cacheOffer;  \r\n        }\r\n        else {\r\n            return null; \/\/If null check again later\/\/                      }}<\/pre>\n<p>You can find more information about Platform cache in the reference section.<\/p>\n<h2>Client-Side Cached Apex Requests<\/h2>\n<p>For custom components, client-side caching provides a performance boost and helps scale, as it reduces the number of XHR requests back to the server for data. With LWC client-side cache can be enabled in Apex as shown below:<\/p>\n<pre>&lt;pre&gt;\r\n  @AuraEnabled(cacheable=true)\r\n    public static List&lt;String&gt; getMetrics() { \r\n    \/\/your code here..\r\n&lt;\/pre&gt;<\/pre>\n<p>This caches data in the client for the component and avoids having to make XHRs to fetch data as long as the data is still fresh.<\/p>\n<h2>Server side optimizations<\/h2>\n<p>Scale and user experience depend heavily on backend code. In this case, we\u2019re talking about Apex. There are a few ways to implement server-side optimizations:<\/p>\n<ul>\n<li>Reduce waiting time in the client by reducing processing in Apex.<\/li>\n<li>Reduce multiple calls to Apex.<\/li>\n<li>Processing in Apex @AuraEnabled methods should be reduced.<\/li>\n<li>Shift some of the processing to the client-side controller.<\/li>\n<\/ul>\n<p>For example, if user information is required on a page, having multiple Apex methods to return pieces of user data such as username, etc., will cause multiple requests from the client. For users in remote locations having different network bandwidths, this can slow down the page load.<\/p>\n<p>A better option is to have one method which returns all required data in one XHR request.<\/p>\n<p>\n\t\t\t  <span class=\"postimagessection_specify alignnone size-full wp-image-193224\" >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211101403\/controller-e1581441266784.png\" class=\"postimages\" width=\"1400\" height=\"328\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<h2>Conclusion<\/h2>\n<p>Lightning applications using component-based pages are a huge productivity boost for users. Under conditions of heavy user activity in large implementations, extra precautions are required to ensure Lightning applications and the Org scales\/performs well; this provides a great user experience.<\/p>\n<h3>References<\/h3>\n<p><a href=\"https:\/\/help.salesforce.com\/articleView?id=000316034&amp;type=1&amp;mode=1\">Improve Performance and Speed in Lightning<\/a><br \/>\nPlatform Cache Blog <a href=\"https:\/\/developer.salesforce.com\/blogs\/2019\/08\/scaling-data-access-with-app-layer-cache.html\">Scaling Data Access With App Layer Cache<\/a><\/p>\n<h3>About the Author<\/h3>\n<p><strong>Anil Jacob <\/strong>is a principal engineer on the Frontier Scale team responsible to scaling Salesforce implementations for customers. Anil has been with Salesforce for over 10 years focusing on architecture, large data volumes, application design, Lightning, and APIs. Prior to Salesforce, Anil worked at Intuit, consulting at BEA for Weblogic virtualization, and Wells Fargo Investments.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog post provides guidance to architects, developers, and administrators in creating and designing Lightning pages that scale and perform well. Where we used to have Visualforce and multi-page applications, we now have Lightning Web Components (LWC) and single-page applications (SPA). With SPA, a user can do most of the work from the same page [&hellip;]<\/p>\n","protected":false},"author":3525,"featured_media":193232,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2528,2766],"tags":[2674,2586,1389,1120,2679],"coauthors":[],"class_list":["post-193201","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-integration-apis","category-tutorials","tag-customer-360-platform","tag-lightning-web-components","tag-sales-cloud","tag-service-cloud","tag-spring-20"],"podcast_audio":{"audio_url":"","duration":""},"featured_image":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png?w=200","related_posts":[{"post":{"ID":201348,"post_author":"3687","post_date":"2024-04-30 09:00:47","post_date_gmt":"2024-04-30 15:00:47","post_content":"Security is one of the most critical elements of storing your data on a device. We\u2019re excited to announce that in Spring \u201924, Salesforce is introducing the <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.mobile_offline.meta\/mobile_offline\/use_biometricsservice.htm\">BiometricsService<\/a> mobile capability! BiometricsService enables developers to add additional security measures to the data being stored on Lightning web components (LWCs).\r\n\r\nLet\u2019s say, for example, that you are looking to build an LWC to store sensitive data, such as a contact\u2019s physical address and identification information. However, these are sensitive data points that you wouldn\u2019t want just anyone to have access to. Through BiometricsService, you will be able to use security measures, such as FaceID and fingerprint scanning, to add additional security to the data being processed within your Salesforce mobile apps.\r\n\r\nLet\u2019s take a look at how!\r\n<h2>Work with the BiometricsService API<\/h2>\r\nBefore we discuss how to use the BiometricsService API, let\u2019s walk through a quick example of BiometricsService using <a href=\"https:\/\/github.com\/trailheadapps\/dreamhouse-lwc\">Dreamhouse<\/a>, a sample app that features some LWCs for mobile use cases in a real estate context.\r\n\r\nSay that you\u2019re a real estate agent who has closed a deal with a client on a new home, and you are updating the Opportunity information in Salesforce. To process the transaction, you will need to collect the following paperwork and personal details on the Opportunity record.\r\n<ul>\r\n \t<li>Purchase agreements<\/li>\r\n \t<li>Buyer and seller details\r\n<ul>\r\n \t<li>Phone numbers<\/li>\r\n \t<li>Current residency details<\/li>\r\n<\/ul>\r\n<\/li>\r\n \t<li>Purchased home address information<\/li>\r\n \t<li>And more!<\/li>\r\n<\/ul>\r\nYou are filling out these details on the spot, and given the sensitive nature of the data you are updating, you do not want just anyone to have access to this information when they are accessing your device. As you go from one place to another, you will need to access this information, but what if you misplace your phone or someone else not authorized to access this data attempts to do so? How can you stop this?\r\n\r\nEnter BiometricsService! Using the BiometricsService API, you can add security measures, such as fingerprint unlock or Face ID scan, so that you have an additional security measure on the device at all times. You are protecting sensitive data access on the Opportunity record directly via the LWC.\r\n\r\n<i><b>Note:<\/b> BiometricsService is a mobile-only capability via LWC. It does not support biometrics unlock of LWCs when configured via web devices using features like fingerprint scan via Touch ID on desktop.<\/i>\r\n<h2><b>Configure the BiometricsService API <\/b><\/h2>\r\nThe BiometricsService API enables you to verify device ownership when interfacing with an LWC. This can be done through two steps:\r\n<ol>\r\n \t<li>Configure your LWC HTML template to include a <code>lightning-button<\/code> base component. This will be used to prompt the user for biometric authentication.<\/li>\r\n \t<li>Connect that button with the JavaScript API that BiometricsService provides to invoke auth capabilities.<\/li>\r\n<\/ol>\r\n<i><b>Note:<\/b> To use BiometricsService, the end user looking to use the functionality on a mobile device must first have a fingerprint or Face ID scan pre-configured on the device. Reference the official <a href=\"https:\/\/support.apple.com\/guide\/iphone\/set-up-touch-id-iph672384a0b\/ios\">iOS<\/a> and <a href=\"https:\/\/developer.android.com\/codelabs\/biometric-login#0\">Android<\/a> device on how to configure. <\/i>\r\n\r\nLet\u2019s dive into more details on these steps!\r\n<h3><b>Step 1: Configure your LWC HTML template<\/b><\/h3>\r\nFor this LWC, we\u2019ll use the <code>handleVerifyClick<\/code> onclick method call, which invokes the API we\u2019ll need to begin using BiometricsService on LWC. This onclick method can be housed in the <code>lightning-button<\/code> HTML base component which, when invoked, will begin prompting the user for device ownership.\r\n\r\n<i><b>Tip:<\/b> When prompting biometric auth, you would want it to be a very upfront action for the end user trying to access the LWCs holding the aforementioned sensitive data. As such, a general recommendation is to house the <code>lightning-button<\/code> component within a <code>lightning-card<\/code> base component, which will render a card-style modal as a banner at the forefront for users when attempting to access sensitive data.<\/i>\r\n<pre language=\"html\">&lt;template&gt;\r\n  &lt;lightning-card title=&quot;Biometrics Service Demo&quot; icon-name=&quot;custom:privately_shared&quot;&gt;\r\n    &lt;div class=&quot;slds-var-m-around_medium&quot;&gt;\r\n      Use device biometrics capabilities to verify current user is indeed device owner:\r\n      &lt;lightning-button\r\n        variant=&quot;brand&quot;\r\n        label=&quot;Verify&quot; \r\n        title=&quot;Verify device ownership using biometrics&quot;\r\n        onclick={handleVerifyClick}\r\n        class=&quot;slds-var-m-left_x-small&quot;&gt;\r\n      &lt;\/lightning-button&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;slds-var-m-around_medium&quot;&gt;\r\n      &lt;lightning-formatted-text value={status}&gt;&lt;\/lightning-formatted-text&gt;\r\n    &lt;\/div&gt;\r\n  &lt;\/lightning-card&gt;    \r\n&lt;\/template&gt;\r\n<\/pre>\r\nOnce those HTML configs are set, you will get a view of BiometricsService running within your LWC. Here is a sample view of the HTML payload from above, running in iOS:\r\n\r\n<img src=\"https:\/\/developer.salesforce.com\/blogs\/wp-content\/uploads\/2024\/04\/image-2024-04-29T143243.496-507x1000.png\" alt=\"The BiometricsService mobile capability running on LWC in iOS\" width=\"507\" height=\"1000\" class=\"alignnone size-medium wp-image-201349\" \/>\r\n<h3><b>Step 2: Connect your user interface with the BiometricsService API<\/b><\/h3>\r\nIn Step 1, we configured the <code>handleVerifyClick<\/code> method on the LWC in the HTML file. Here we will need to connect that method to the BiometricsService API that we import via <code>mobileCapabilities<\/code>.\r\n\r\nYou can use the following API calls to interface with BiometricsService.\r\n<table>\r\n<tbody>\r\n<tr>\r\n<td>API Call<\/td>\r\n<td>Params<\/td>\r\n<td>Response<\/td>\r\n<td>Description<\/td>\r\n<\/tr>\r\n<tr>\r\n<td><code><a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-biometricsservice-factory.html\">getBiometricsService<\/a><\/code><\/td>\r\n<td>None<\/td>\r\n<td><code>BiometricsService<\/code><\/td>\r\n<td>Initializes Biometrics Service in your JavaScript class after importing the module from the <a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-mobilecapabilities.html\">lightning\/MobileCapabilities module<\/a>.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td><code><a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-biometricsservice-isavailable.html\">isAvailable<\/a><\/code><\/td>\r\n<td>None<\/td>\r\n<td><code>true \/ false<\/code><\/td>\r\n<td>Allows you to check whether BiometricsService is available on device to invoke. Reference our <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.mobile_offline.meta\/mobile_offline\/use_biometricsservice_compatibility.htm\">Compatibility &amp; Requirements<\/a> for more details on list of supported devices.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td><code><a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-biometricsservice-isbiometricsready.html\">isBiometricsReady<\/a><\/code><\/td>\r\n<td>None<\/td>\r\n<td><code>true \/ false<\/code><\/td>\r\n<td>Checks whether Biometrics is ready to use after it has been initialized.<\/td>\r\n<\/tr>\r\n<tr>\r\n<td><code><a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-biometricsservice-checkuserisdeviceowner.html\">checkUserIsDeviceOwner<\/a><\/code><\/td>\r\n<td>String (<a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-biometricsservice-data-types.html\">Options<\/a>)<\/td>\r\n<td><code>true \/ false<\/code><\/td>\r\n<td>Allows you to check whether the fingerprint or Face ID scanned matches with the fingerprint or Face ID scan that is provided by the user on the mobile device.<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\nWhen using this API in your JavaScript LWC code, it would look like this:\r\n<pre language=\"javascript\">import { LightningElement } from 'lwc';\r\nimport { getBiometricsService } from 'lightning\/mobileCapabilities';\r\n\r\nexport default class NimbusPluginBiometricsService extends LightningElement {\r\n    status;\r\n    biometricsService;\r\n\r\n    connectedCallback() {\r\n      this.biometricsService = getBiometricsService();\r\n    }\r\n\r\n    handleVerifyClick() {\r\n      if (this.biometricsService.isAvailable()) {\r\n        const options = {\r\n          permissionRequestBody: \"Required to confirm device ownership.\",\r\n          additionalSupportedPolicies: ['PIN_CODE']\r\n        };\r\n        this.biometricsService.checkUserIsDeviceOwner(options)\r\n          .then((result) =&gt; {\r\n            \/\/ Do something with the result\r\n            if (result === true) {\r\n              this.status = \"\u2714 Current user is device owner.\"\r\n            } else {\r\n              this.status = \"\ud800\udd02 Current user is NOT device owner.\"\r\n            }\r\n          })\r\n          .catch((error) =&gt; {\r\n            \/\/ Handle errors\r\n            this.status = 'Error code: ' + error.code + '\\nError message: ' + error.message;\r\n          });\r\n      } else {\r\n        \/\/ service not available\r\n        this.status = 'Problem initiating Biometrics service. Are you using a mobile device?';\r\n      }\r\n    }\r\n}\r\n<\/pre>\r\n<b>Important Notes<\/b>\r\n<ul>\r\n \t<li>The <code>options<\/code> constant is a required parameter, and when checking device ownership, the <code>addionalSupportedPolicies<\/code> object allows you to configure the fallback options in the event that the biometrics scan fails. In this case, adding <code>PIN_CODE<\/code> in the object array will alert BiometricsService to prompt for the device pin code as the fallback.<\/li>\r\n \t<li>If the barcode scan fails, it will return a set of failure codes. Reference <a href=\"https:\/\/developer.salesforce.com\/docs\/platform\/lwc\/guide\/reference-lightning-biometricsservice-constants.html#biometricsservicefailurecode\">BiometricsServiceFailureCodes<\/a> for more details.<\/li>\r\n<\/ul>\r\n<h2>BiometricsService compatibility<\/h2>\r\nBiometricsService is available in the Spring \u201924 release across the Salesforce Mobile App, Salesforce Mobile App Plus, and Mobile Publisher offerings. See the <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.mobile_offline.meta\/mobile_offline\/capabilities.htm\">Mobile Capabilities Compatibility Summary<\/a> to stay up to date with its availability across our Salesforce mobile apps.\r\n<h2><b>Conclusion<\/b><\/h2>\r\nWe hope that you\u2019ve enjoyed this blog post and that you are looking forward to using the biometrics scanning capabilities on your LWC for mobile. To get started:\r\n<ul>\r\n \t<li><b>Dive in!<\/b> Take a look at our <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.mobile_offline.meta\/mobile_offline\/use_biometricsservice.htm\">example LWCs<\/a> to get familiar with the plugin.<\/li>\r\n \t<li><b>Personalize it!<\/b> Take BiometricsService capabilities and expand on them to customize them for your business needs.<\/li>\r\n \t<li><b>Reach out!<\/b> If you have any questions, comments, or ideas, you can connect with us in the <a href=\"https:\/\/trailhead.salesforce.com\/trailblazer-community\/groups\/0F9300000001qepCAA?tab=discussion&amp;sort=LAST_MODIFIED_DATE_DESC\">Salesforce Mobile Trailblazer Community<\/a>.<\/li>\r\n<\/ul>\r\nTo learn more about Salesforce\u2019s mobile offerings, check out the <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.mobile_offline.meta\/mobile_offline\/intro.htm\">Mobile and Offline Developer Guide<\/a>.\r\n<h2><b>About the author<\/b><\/h2>\r\n<b>Ashwin Nair <\/b>is a<b> <\/b>Product Manager at Salesforce focused on Salesforce Mobile. He is currently working on mobile platform experiences and has been in the web and mobile development space for over seven years. Follow him on <a href=\"https:\/\/www.linkedin.com\/in\/ashwin-nair\/\">LinkedIn<\/a>.","post_title":"Introducing the BiometricsService Mobile Capability","post_excerpt":"The BiometricsService mobile capability enables developers to add additional security measures to the data being stored on LWCs.","post_status":"publish","comment_status":"open","ping_status":"closed","post_password":"","post_name":"introducing-the-biometricsservice-mobile-capability","to_ping":"","pinged":"","post_modified":"2025-11-05 02:13:27","post_modified_gmt":"2025-11-05 09:13:27","post_content_filtered":"","post_parent":0,"guid":"https:\/\/developer.salesforce.com\/blogs\/?p=201348","menu_order":0,"post_type":"post","post_mime_type":"","comment_count":"0","filter":"raw","featured_image":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20240429143606\/Single-Headshot-%E2%80%93-Light-1.png?w=1200","link":"https:\/\/developer.salesforce.com\/blogs\/2024\/04\/introducing-the-biometricsservice-mobile-capability","podcast_audio":{"audio_url":"","duration":""},"authors":[{"name":"Ashwin Nair","image_src":"https:\/\/secure.gravatar.com\/avatar\/1e6242e3f9fd391e0e9c61a52fa9bae3e8cfd36444ff402b1dfe843792de92b3?s=24&d=mm&r=g"}]}}],"unstyled_content":"<p>This blog post provides guidance to architects, developers, and administrators in creating and designing Lightning pages that scale and perform well. Where we used to have Visualforce and multi-page applications, we now have Lightning Web Components (LWC) and single-page applications (SPA).<\/p>\n<p>With SPA,<b> <\/b>a user can do most of the work from the same page without navigating to other pages. This is a huge productivity gain and can result in a great user experience; however, proper design is recommended to ensure large volumes of requests do not pose any scale or performance challenges.<\/p>\n<p>SPAs are made up of components that receive and send data to the server using XML HTTP Requests (XHR).<br \/>\nWhen a page loads, components can be rendered in parallel, making multiple XHRs to the server in order to retrieve data and metadata.<\/p>\n<p>In implementations with a large user base using the Lightning application concurrently, the component architecture can create a great number of network requests in the Org. Proper design is recommended to ensure large volumes of requests do not pose any scale or performance challenges.<\/p>\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210144743\/components-e1581371286487.png\" width=\"700\" height=\"297\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n\n<h2>A Word about Scale and Performance<\/h2>\n<p>Scaling is the ability of a system to perform consistently under load. Lack of ability to scale can impact all processes in a system and can impact business growth. Performance<b> <\/b>is the time taken for a request to complete. Your user<b> <\/b>experience can be negatively impacted by UI applications that don\u2019t perform well.<\/p>\n<h3>Factors that Impact Lightning scale<\/h3>\n<p>In implementations with a large user base, there are certain aspects of page design that can be optimized to scale. A few are summarized here:<\/p>\n<ol>\n<li>Number of visible components on page load<\/li>\n<li>Custom list views with lots of data<\/li>\n<li>Related Lists, Quick Links<\/li>\n<li>Custom Components<\/li>\n<li>APEX &amp; backend<\/li>\n<li>UI Forms<\/li>\n<\/ol>\n<p>Below you will find recommendations for each of these page design ideas.<\/p>\n<p>Number of components on a page<\/p>\n<p>Based on an analysis of various customer implementations, we\u2019ve found that Lightning pages with the right amount of components load faster, and Lightning implementation scales well overall. So how do we determine the right number of components?<\/p>\n\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210164330\/visible-components-e1581378233595.png\" width=\"700\" height=\"302\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<h3>Solution 1: Lazy Loading Tabs<\/h3>\n<p>Showing actionable components as visible components is both efficient and can result in a better user experience when implemented correctly. This is called lazy loading: wherein components are shown only on demand or progressively as the user navigates through a task. One lazy loading technique is to use tabs and nest components under tabs. Components nested in tabs do not execute any XHRs and are not part of the DOM.<\/p>\n<h3>Solution 2: Lazy Loading With Personas<\/h3>\n<p>Another way to load components efficiently is to group components based on user persona rather than functionality. This way only higher priority components needed by a user to complete a certain tasks are visible on page load.<\/p>\n<p>In the example below, we see components relevant for an insurance agent. Products are what the agent wants to access quickly. Components that are secondary to a user\u2019s needs, such as claims, details, and reports &#8211; can be in tabs.<\/p>\n\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210164703\/visible-e1581378449157.png\" width=\"652\" height=\"413\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n\n<h2>Lazy Loading in Custom Components<\/h2>\n<p>LWC provides an easy way to do lazy loading with the <code>if:true<\/code><b> <\/b>directive<b>.<\/b><\/p>\n<p>In the code below, ensure the property <code>showForm<\/code><i> <\/i>is false, <code>c:formcompoment<\/code> and all its HTML elements are not part of the DOM. <code>c:formcompoment<\/code> is a custom component stub we are using for this example. This reduces the number of DOM elements, which improves page load time, and avoids XHRs to the server, allowing for scale.<\/p>\n<p><b>TIP: <\/b><i>showForm<\/i> variable in Javascript can be switched between true or false with a button click.<\/p>\n<p>Lightning Web Component<\/p>\n<pre>&lt;template if:true={showForm}&gt;\r\n    &lt;c:formcomponent&gt; - \/\/component is not visible unless showForm == true\r\n&lt;\/template&gt;<\/pre>\n<p>Aura component<\/p>\n<pre>&lt;aura:if isTrue=\"{!v.showForm}\"&gt;\r\n    &lt;c:formcomponent&gt; - \/\/component is not visible unless showForm == true\r\n&lt;\/aura:if&gt;<\/pre>\n<h2>Long custom list views<\/h2>\n<p>Custom lists with a large number of rows can be a performance and scale issue. Based on our analysis, a list of 2000 rows takes approximately 10 seconds to render. Much of the time is spent in the browser because Javascript takes time to iterate each row item and render.<\/p>\n<p>The list shown here has 2000 rows. Using browser tools to measure<b> <\/b>list rendering time we see that about 9 seconds are spent on Javascript and 1 second on browser-style recalculations.<\/p>\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210165105\/oppor-e1581378689766.png\" width=\"700\" height=\"232\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200210165109\/9secs-e1581378736323.png\" width=\"700\" height=\"92\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p><i><strong>NOTE:<\/strong> This is a sample. Time taken is subject to list types and other factors.<\/i><\/p>\n<p>Nine seconds is too long for most users, so here are a few effective solutions to reduce time to perform.<\/p>\n<h3>Solution 1: Custom Lists<\/h3>\n<p>We can use LWC for custom Lists. Javascript processing is faster in LWC, so iterating the list items will be faster. LWC provides ListUI module to import standard listviews. For custom listviews, pagination is highly recommended.<\/p>\n<h3>Solution 2: Pagination<\/h3>\n<p>Paginate the list data on the server and on the client. Pagination shows less data at a time, making for a better user experience. With pagination, a small number of list rows can be rendered on the client side. Based on the analysis, lists with 50 or fewer rows render quickly, resulting in a better user experience.<\/p>\n<p>Below is sample code demonstrating pagination in Javascript for a custom listview in LWC.<\/p>\n\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211100824\/DIckenson-2-e1581440915690.png\" width=\"700\" height=\"130\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p>Below is sample Javascript code for implementing pagination in a custom list.<\/p>\n<pre>&lt;pre&gt;\r\nimport { LightningElement, track, wire, api } from \"lwc\";\r\nmport getContacts from \"@salesforce\/apex\/ListViewPlusDataController.getContacts\";\r\nimport { getObjectInfo } from \"lightning\/uiObjectInfoApi\";\r\nimport CONTACT_OBJECT from \"@salesforce\/schema\/Contact\";\r\nexport default class Listviewplus extends LightningElement {\r\n.....\r\n@wire(getContacts)\r\n  wiredContacts({ error, data }) {    \r\n    \r\n    if (error) {\r\n      this.error = error;\r\n    } else if (data) {\r\n      this.contactsbackup = data;\r\n      this.contacts = data.slice(1, 50); \r\n    }\r\n .....\r\n @api\r\n  pressRight(left, right) {\r\n    this.contacts = this.contactsbackup.slice(left, right);\r\n  }\r\n @api\r\n  pressLeft(left, right) {\r\n    this.contacts = this.contactsbackup.slice(left, right);\r\n  }\r\n  &lt;pre&gt;<\/pre>\n<p>Pagination can be as simple as using buttons to move through the list as shown here.<\/p>\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211101134\/50-of-2000-e1581441103219.png\" width=\"514\" height=\"110\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<br \/>\nSample HTML code to render the list controls.<\/p>\n<pre> &lt;div&gt;\r\n   &lt;h6 &gt;\r\n            {leftIndex} - {rightIndex} of {numrecords}&lt;\/h6&gt;\r\n &lt;\/div&gt;\r\n &lt;div&gt;\r\n    &lt;lightning-button-icon title=\"Go To Previous Page Of This List\" \r\n        icon-name=\"utility:left\"  size=\"large\" alternative-text=\"refresh this view\" \r\n        onclick={pressLeft} disabled={leftDisabled}&gt;&lt;\/lightning-button-icon&gt;\r\n &lt;\/div&gt;\r\n \r\n &lt;div&gt;\r\n       &lt;lightning-button-Icon title=\"Go To Next Page Of This List\" \r\n       icon-name=\"utility:right\"  size=\"large\" \r\n       alternative-text=\"refresh this view\" \r\n       onclick={pressRight} disabled={rightDisabled}&gt;&lt;\/lightning-button-Icon&gt;\r\n &lt;\/div&gt;<\/pre>\n<h2>Optimizing Quick Links<\/h2>\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211101235\/quick-links-e1581441167880.png\" width=\"700\" height=\"93\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<p>Quick links are great, they make it easy to access related data quickly. Quick links show counts of records for related objects and show a partial list on mouse hover.<\/p>\n<p>In implementations with a large number of concurrent users, it is advisable to configure quick links into a tab. <b> <\/b>This prevents retrieving object record counts as well as accidental hovering on the quick links and thereby avoiding XHRs<b> <\/b>back to the server<b>.<\/b><\/p>\n<p>Let us look at how much page load time is saved by moving the Related quick links to its own tab.<\/p>\n<h3>Measuring the benefits<\/h3>\n<p>We did a simple test to measure the impact of page design on page performance. This test was conducted on a page containing 8 components, including the Related List quick links component (more details on that below).<\/p>\n<table>\n<tbody>\n<tr>\n<th>A<\/th>\n<th>Quick Links on the main page<\/th>\n<th>Quick links in a tab<\/th>\n<th>Improvement<\/th>\n<\/tr>\n<\/tbody>\n<colgroup>\n<col \/>\n<col \/>\n<col \/>\n<col \/><\/colgroup>\n<tbody>\n<tr>\n<td>Page Load Time (seconds)<\/td>\n<td>2.6<\/td>\n<td>2.2<\/td>\n<td>0.4<\/td>\n<\/tr>\n<tr>\n<td>Number Of XHRs on page load<\/td>\n<td>42<\/td>\n<td>35<\/td>\n<td>7<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We re-configured the page by moving the Related List quick links into its own tab<b>,<\/b> which resulted in a 0.4 second improvement. This is a direct result of a reduced number of XHR calls made during page load, as the Related List quick links component does not get rendered.<\/p>\n<p><em><strong>NOTE:<\/strong> This data is from basic tests relevant only for this post. Results will vary based on different factors.<\/em><\/p>\n<h2>Creating Custom Components that Scale<\/h2>\n<p>Custom components are useful for creating customized business applications that leverage the power of the Salesforce platform.<\/p>\n<p>LWC is a great framework for creating new custom components. Apart from the scale and performance benefits, development is made much easier with our provided <a href=\"https:\/\/developer.salesforce.com\/docs\/atlas.en-us.lightning.meta\/lightning\/lightning_overview.htm\">Lightning Web Component Base Components<\/a>, such as <code>listView<\/code>, <code>recordForm<\/code>, and more.<\/p>\n<p>These highly-optimized components help your clients retrieve data without complex backend code. For more complex business transactions, LWC can always use Apex<b>.<\/b><\/p>\n<h2>Using Platform Cache<\/h2>\n<p>For custom components that have to be visible on page load try using platform cache in Apex.<b> <\/b>Platform cache provides simple API for retrieval and insertion into cache. Requests from custom components are retrieved from the cache, avoiding SOQL queries and database connection setup.<\/p>\n<p>Cache retrieval is usually less than<b> <\/b>10ms,<b> <\/b>improving component render time and protecting database resources from being impacted when a large number of users load their pages with custom components. Let\u2019s look at some sample Platform cache code in Apex:<\/p>\n<pre>public static String getOffers(String agentId) {\r\n        String cacheOffer = (String)Cache.Org.get(agentId); \r\n\r\n\/\/Cast to String since we serialized the value.\r\n        if (cacheOffer != null) {\r\n             return cacheOffer;  \r\n        }\r\n        else {\r\n            return null; \/\/If null check again later\/\/                      }}<\/pre>\n<p>You can find more information about Platform cache in the reference section.<\/p>\n<h2>Client-Side Cached Apex Requests<\/h2>\n<p>For custom components, client-side caching provides a performance boost and helps scale, as it reduces the number of XHR requests back to the server for data. With LWC client-side cache can be enabled in Apex as shown below:<\/p>\n<pre>&lt;pre&gt;\r\n  @AuraEnabled(cacheable=true)\r\n    public static List&lt;String&gt; getMetrics() { \r\n    \/\/your code here..\r\n&lt;\/pre&gt;<\/pre>\n<p>This caches data in the client for the component and avoids having to make XHRs to fetch data as long as the data is still fresh.<\/p>\n<h2>Server side optimizations<\/h2>\n<p>Scale and user experience depend heavily on backend code. In this case, we\u2019re talking about Apex. There are a few ways to implement server-side optimizations:<\/p>\n<ul>\n<li>Reduce waiting time in the client by reducing processing in Apex.<\/li>\n<li>Reduce multiple calls to Apex.<\/li>\n<li>Processing in Apex @AuraEnabled methods should be reduced.<\/li>\n<li>Shift some of the processing to the client-side controller.<\/li>\n<\/ul>\n<p>For example, if user information is required on a page, having multiple Apex methods to return pieces of user data such as username, etc., will cause multiple requests from the client. For users in remote locations having different network bandwidths, this can slow down the page load.<\/p>\n<p>A better option is to have one method which returns all required data in one XHR request.<\/p>\n<p>\n\t\t\t  <span >\n\t\t\t    <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211101403\/controller-e1581441266784.png\" width=\"1400\" height=\"328\" alt=\"\" \/>\n\t\t\t  <\/span>\n\t\t\t<\/p>\n<h2>Conclusion<\/h2>\n<p>Lightning applications using component-based pages are a huge productivity boost for users. Under conditions of heavy user activity in large implementations, extra precautions are required to ensure Lightning applications and the Org scales\/performs well; this provides a great user experience.<\/p>\n<h3>References<\/h3>\n<p><a href=\"https:\/\/help.salesforce.com\/articleView?id=000316034&amp;type=1&amp;mode=1\">Improve Performance and Speed in Lightning<\/a><br \/>\nPlatform Cache Blog <a href=\"https:\/\/developer.salesforce.com\/blogs\/2019\/08\/scaling-data-access-with-app-layer-cache.html\">Scaling Data Access With App Layer Cache<\/a><\/p>\n<h3>About the Author<\/h3>\n<p><strong>Anil Jacob <\/strong>is a principal engineer on the Frontier Scale team responsible to scaling Salesforce implementations for customers. Anil has been with Salesforce for over 10 years focusing on architecture, large data volumes, application design, Lightning, and APIs. Prior to Salesforce, Anil worked at Intuit, consulting at BEA for Weblogic virtualization, and Wells Fargo Investments.<\/p>\n\n","acf":{"canonicalid":"","language":"english","audio_url":"https:\/\/a.sfdcstatic.com\/developer-website\/blog-audio\/193201\/193201.mp3","hash":"e5350c18cac27ec8773f9fa252666bd9","transcription_id":"ff629a01-7985-435d-8ae4-d3397bda442b","ready":true},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.3 (Yoast SEO v25.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Designing Lightning Pages for Scale - Salesforce Developers Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Designing Lightning Pages for Scale\" \/>\n<meta property=\"og:description\" content=\"This blog post provides guidance to architects, developers, and administrators in creating and designing Lightning pages that scale and perform well. Where we used to have Visualforce and multi-page applications, we now have Lightning Web Components (LWC) and single-page applications (SPA). With SPA, a user can do most of the work from the same page [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale\" \/>\n<meta property=\"og:site_name\" content=\"Salesforce Developers Blog\" \/>\n<meta property=\"article:published_time\" content=\"2020-02-11T18:00:22+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-05T09:20:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png\" \/>\n\t<meta property=\"og:image:width\" content=\"200\" \/>\n\t<meta property=\"og:image:height\" content=\"200\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Anil Jacob\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@SalesforceDevs\" \/>\n<meta name=\"twitter:site\" content=\"@SalesforceDevs\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Anil Jacob\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale\",\"url\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale\",\"name\":\"Designing Lightning Pages for Scale - Salesforce Developers Blog\",\"isPartOf\":{\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#primaryimage\"},\"image\":{\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#primaryimage\"},\"thumbnailUrl\":\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png\",\"datePublished\":\"2020-02-11T18:00:22+00:00\",\"dateModified\":\"2025-11-05T09:20:59+00:00\",\"author\":{\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/#\/schema\/person\/97c7f373278dd22f26fad8124b761521\"},\"breadcrumb\":{\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#primaryimage\",\"url\":\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png\",\"contentUrl\":\"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png\",\"width\":200,\"height\":200},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/developer.salesforce.com\/blogs\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Designing Lightning Pages for Scale\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/#website\",\"url\":\"https:\/\/developer.salesforce.com\/blogs\/\",\"name\":\"Salesforce Developers Blog\",\"description\":\"Elevating developer skills and connecting with the Salesforce Developers community\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/developer.salesforce.com\/blogs\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/#\/schema\/person\/97c7f373278dd22f26fad8124b761521\",\"name\":\"Anil Jacob\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/developer.salesforce.com\/blogs\/#\/schema\/person\/image\/6c6a5aaf4eaac2b26effb56691e93f02\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/ae75b583a3e46f7d27388211487d57588ec84070ffe790f2b1bfcb9e4b3b4fa6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/ae75b583a3e46f7d27388211487d57588ec84070ffe790f2b1bfcb9e4b3b4fa6?s=96&d=mm&r=g\",\"caption\":\"Anil Jacob\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/aniljacob1\/\"],\"url\":\"https:\/\/developer.salesforce.com\/blogs\/author\/anil-jacob\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Designing Lightning Pages for Scale - Salesforce Developers Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale","og_locale":"en_US","og_type":"article","og_title":"Designing Lightning Pages for Scale","og_description":"This blog post provides guidance to architects, developers, and administrators in creating and designing Lightning pages that scale and perform well. Where we used to have Visualforce and multi-page applications, we now have Lightning Web Components (LWC) and single-page applications (SPA). With SPA, a user can do most of the work from the same page [&hellip;]","og_url":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale","og_site_name":"Salesforce Developers Blog","article_published_time":"2020-02-11T18:00:22+00:00","article_modified_time":"2025-11-05T09:20:59+00:00","og_image":[{"width":200,"height":200,"url":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png","type":"image\/png"}],"author":"Anil Jacob","twitter_card":"summary_large_image","twitter_creator":"@SalesforceDevs","twitter_site":"@SalesforceDevs","twitter_misc":{"Written by":"Anil Jacob","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale","url":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale","name":"Designing Lightning Pages for Scale - Salesforce Developers Blog","isPartOf":{"@id":"https:\/\/developer.salesforce.com\/blogs\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#primaryimage"},"image":{"@id":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#primaryimage"},"thumbnailUrl":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png","datePublished":"2020-02-11T18:00:22+00:00","dateModified":"2025-11-05T09:20:59+00:00","author":{"@id":"https:\/\/developer.salesforce.com\/blogs\/#\/schema\/person\/97c7f373278dd22f26fad8124b761521"},"breadcrumb":{"@id":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#primaryimage","url":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png","contentUrl":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png","width":200,"height":200},{"@type":"BreadcrumbList","@id":"https:\/\/developer.salesforce.com\/blogs\/2020\/02\/designing-lightning-pages-for-scale#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/developer.salesforce.com\/blogs"},{"@type":"ListItem","position":2,"name":"Designing Lightning Pages for Scale"}]},{"@type":"WebSite","@id":"https:\/\/developer.salesforce.com\/blogs\/#website","url":"https:\/\/developer.salesforce.com\/blogs\/","name":"Salesforce Developers Blog","description":"Elevating developer skills and connecting with the Salesforce Developers community","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/developer.salesforce.com\/blogs\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/developer.salesforce.com\/blogs\/#\/schema\/person\/97c7f373278dd22f26fad8124b761521","name":"Anil Jacob","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.salesforce.com\/blogs\/#\/schema\/person\/image\/6c6a5aaf4eaac2b26effb56691e93f02","url":"https:\/\/secure.gravatar.com\/avatar\/ae75b583a3e46f7d27388211487d57588ec84070ffe790f2b1bfcb9e4b3b4fa6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ae75b583a3e46f7d27388211487d57588ec84070ffe790f2b1bfcb9e4b3b4fa6?s=96&d=mm&r=g","caption":"Anil Jacob"},"sameAs":["https:\/\/www.linkedin.com\/in\/aniljacob1\/"],"url":"https:\/\/developer.salesforce.com\/blogs\/author\/anil-jacob"}]}},"jetpack_featured_media_url":"https:\/\/d259t2jj6zp7qm.cloudfront.net\/images\/20200211120313\/guage.png","authors":[{"name":"Anil Jacob","image_src":"https:\/\/secure.gravatar.com\/avatar\/ae75b583a3e46f7d27388211487d57588ec84070ffe790f2b1bfcb9e4b3b4fa6?s=24&d=mm&r=g"}],"_links":{"self":[{"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/posts\/193201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/users\/3525"}],"replies":[{"embeddable":true,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/comments?post=193201"}],"version-history":[{"count":23,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/posts\/193201\/revisions"}],"predecessor-version":[{"id":194108,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/posts\/193201\/revisions\/194108"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/media\/193232"}],"wp:attachment":[{"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/media?parent=193201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/categories?post=193201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/tags?post=193201"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/developer.salesforce.com\/blogs\/wp-json\/wp\/v2\/coauthors?post=193201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}