{"id":13064,"date":"2026-07-31T09:15:17","date_gmt":"2026-07-31T09:15:17","guid":{"rendered":"https:\/\/www.greytrix.com\/blogs\/salesforce\/?p=13064"},"modified":"2026-07-31T09:15:18","modified_gmt":"2026-07-31T09:15:18","slug":"how-to-write-bulkified-apex-code-in-salesforce-to-avoid-governor-limits","status":"publish","type":"post","link":"https:\/\/www.greytrix.com\/blogs\/salesforce\/2026\/07\/31\/how-to-write-bulkified-apex-code-in-salesforce-to-avoid-governor-limits\/","title":{"rendered":"How to Write Bulkified Apex Code in Salesforce to Avoid Governor Limits"},"content":{"rendered":"\n<p>Salesforce runs Apex in a multi-tenant environment, where multiple organizations share the same computing resources. To ensure fair resource usage and maintain platform performance, Salesforce enforces Governor Limits hard limits on database operations, CPU usage, and memory consumption.<\/p>\n\n\n\n<p><strong>Some of the most important governor limits include:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>SOQL queries per transaction:<\/strong> 100 (Synchronous) \/ 200 (Asynchronous)<\/li>\n\n\n\n<li><strong>DML statements per transaction:<\/strong> 150<\/li>\n\n\n\n<li><strong>Records processed per DML statement:<\/strong> 10,000<\/li>\n\n\n\n<li><strong>CPU time:<\/strong> 10,000 ms (Synchronous) \/ 60,000 ms (Asynchronous)<\/li>\n<\/ul>\n\n\n\n<p>This is where Bulkification becomes essential.<\/p>\n\n\n\n<p>Bulkification is the practice of writing Apex code that efficiently processes multiple records in a single transaction, regardless of whether one record or hundreds of records trigger the execution.<\/p>\n\n\n\n<p>Triggers, in particular, can execute on batches of up to 200 records at once &#8211; whether initiated through Data Loader, Salesforce Flow, API integrations, or bulk imports. If your code performs SOQL queries or DML operations inside loops, it scales linearly with the number of records and quickly exceeds governor limits.<\/p>\n\n\n\n<p>In this blog, we&#8217;ll explore common bulkification mistakes, learn the correct implementation patterns, and review best practices for writing governor limit-safe Apex code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">The Classic Anti-Pattern<\/mark><\/strong><\/h2>\n\n\n\n<p>One of the most common mistakes developers make is placing a SOQL query inside a loop.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>trigger AccountTrigger on Account (before update) {\nfor (Account acc : Trigger.new) {\n\n\/\/ SOQL inside a loop\n    List&lt;Contact> contacts = &#91;\n        SELECT Id\n        FROM Contact\n        WHERE AccountId = :acc.Id\n    ];\n\n    if (!contacts.isEmpty()) {\n        acc.Description = 'Has ' + contacts.size() + ' contacts';\n    }\n}\n\n}<\/code><\/pre>\n\n\n\n<p>This may work perfectly while testing with a single record in the Developer Console.<\/p>\n\n\n\n<p>However, updating 200 Accounts causes the trigger to execute 200 SOQL queries, immediately exceeding Salesforce&#8217;s 100 SOQL query limit.<\/p>\n\n\n\n<p><strong>The same issue occurs with DML operations<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>for (Account acc : accountsToUpdate) {\nupdate acc; \/\/ DML inside loop\n}<\/code><\/pre>\n\n\n\n<p>Performing DML inside loops quickly reaches the 150 DML statement limit, causing runtime exceptions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">The Bulkified Version<\/mark><\/strong><\/h2>\n\n\n\n<p>Instead of querying once for every record, query all required data outside the loop.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>trigger AccountTrigger on Account (before update) {\nSet&lt;Id> accountIds = Trigger.newMap.keySet();\n\n\/\/ One query outside the loop\nMap&lt;Id, List&lt;Contact>> contactsByAccount = new Map&lt;Id, List&lt;Contact>>();\n\nfor (Contact c : &#91;\n    SELECT Id, AccountId\n    FROM Contact\n    WHERE AccountId IN :accountIds\n]) {\n\n    if (!contactsByAccount.containsKey(c.AccountId)) {\n        contactsByAccount.put(c.AccountId, new List&lt;Contact>());\n    }\n\n    contactsByAccount.get(c.AccountId).add(c);\n}\n\nfor (Account acc : Trigger.new) {\n\n    List&lt;Contact> related = contactsByAccount.get(acc.Id);\n\n    acc.Description = related != null\n        ? 'Has ' + related.size() + ' contacts'\n        : 'Has 0 contacts';\n}\n}<\/code><\/pre>\n\n\n\n<p>The outcome remains the same, but the trigger now executes only one SOQL query, regardless of whether the batch contains 1 record or 200 records.<\/p>\n\n\n\n<p>This approach dramatically improves scalability and keeps your code within Salesforce governor limits.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Bulkifying DML Operations<\/mark><\/strong><\/h2>\n\n\n\n<p>The same principle applies to DML statements.<\/p>\n\n\n\n<p>Instead of updating records inside the loop, collect them first and perform a single DML operation afterward.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>List&lt;Contact> contactsToUpdate = new List&lt;Contact>();\n\nfor (Account acc : Trigger.new) {\n\n    List&lt;Contact> related = contactsByAccount.get(acc.Id);\n\n    if (related != null) {\n\n        for (Contact c : related) {\n            c.Description = 'Parent account updated';\n            contactsToUpdate.add(c);\n        }\n    }\n}\n\nif (!contactsToUpdate.isEmpty()) {\n    update contactsToUpdate;    \/\/ Single DML statement\n}<\/code><\/pre>\n\n\n\n<p>This approach performs only one update statement, regardless of how many Contact records are modified.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">A Practical Bulkification Checklist<\/mark><\/strong><\/h2>\n\n\n\n<p>When reviewing Apex code for bulk safety, always verify the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Never place SOQL or SOSL queries inside loops. Query all required records once using IN :collectionOfIds.<\/li>\n\n\n\n<li>Never perform DML operations inside loops. Collect records first, then perform a single insert, update, delete, or upsert.<\/li>\n\n\n\n<li>Use Maps for fast lookups instead of repeatedly scanning Lists.<\/li>\n\n\n\n<li>Always assume Trigger.new may contain up to 200 records, not just one.<\/li>\n\n\n\n<li>Test your Apex with bulk data, not only individual records.<\/li>\n\n\n\n<li>Protect against recursive trigger execution using static variables or a Trigger Handler framework.<\/li>\n\n\n\n<li>Review helper classes and utility methods to ensure they are also bulkified. Even a bulk-safe trigger can fail if it calls non-bulkified methods internally.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Conclusion<\/mark><\/strong><\/h2>\n\n\n\n<p>Bulkification isn&#8217;t an advanced optimization technique &#8211; it&#8217;s a fundamental requirement for writing production-ready Apex code.<\/p>\n\n\n\n<p>The guiding principle is simple: database operations such as SOQL queries and DML statements should occur once per transaction, not once per record.<\/p>\n\n\n\n<p>By following bulkification best practices, using collections effectively, and minimizing database interactions, you can build scalable Apex solutions that stay within Salesforce governor limits and perform reliably in high-volume production environments.<\/p>\n\n\n\n<p>By following the above blog instructions, you will be able to learn \u201c<strong>How to Write Bulkified Apex Code in Salesforce to Avoid Governor Limits<\/strong>\u201c. If you still have queries or any related problems, don\u2019t hesitate to contact us at <a href=\"mailto:salesforce@greytrix.com\" target=\"_blank\" rel=\"noreferrer noopener\">salesforce@greytrix.com<\/a>. More details about our integration product are available on <a href=\"https:\/\/www.greytrix.com\/salesforce-cloud-services\/\" target=\"_blank\" rel=\"noreferrer noopener\">our website<\/a> and <a href=\"https:\/\/appexchange.salesforce.com\/appxListingDetail?listingId=a0N30000000psM5EAI\" target=\"_blank\" rel=\"noreferrer noopener\">Salesforce AppExchange<\/a>.<br>We hope you may find this blog resourceful and helpful. However, if you still have concerns and need more help, please contact us at <a href=\"mailto:salesforce@greytrix.com\" target=\"_blank\" rel=\"noreferrer noopener\">salesforce@greytrix.com<\/a>.<\/p>\n\n\n\n<p style=\"text-align: justify\"><b>About Us<\/b><\/br>\n<p><a href=\"https:\/\/www.greytrix.com\/\">Greytrix<\/a> \u2013 a globally recognized and one of the oldest Sage Development Partner and a Salesforce Product development partner offers a wide variety of integration products and services to the end users as well as to the Partners and Sage PSG across the globe. We offer Consultation, Configuration, Training and support services in out-of-the-box functionality as well as customizations to incorporate custom business rules and functionalities that require apex code incorporation into the Salesforce platform.<br><br> Greytrix has some unique solutions for Cloud CRM such as <a href=\"\">Salesforce Sage integration<\/a> for <a href=\"https:\/\/www.greytrix.com\/sage-x3-erp\/integration\/\">Sage X3<\/a>, <a href=\"https:\/\/www.greytrix.com\/salesforce-cloud-services\/sage-100-integration\/\">Sage 100<\/a> and <a href=\"https:\/\/www.greytrix.com\/salesforce-cloud-services\/sage-300-integration\/\">Sage 300 (Sage Accpac)<\/a>. We also offer best-in-class Cloud CRM <a href=\"https:\/\/www.greytrix.com\/salesforce-cloud-services\/crm-development\/\">Salesforce customization and development services<\/a> along with services such as Salesforce <a href=\"https:\/\/www.greytrix.com\/salesforce-cloud-services\/data-migration-support\/\">Data Migration<\/a>, <a href=\"https:\/\/www.greytrix.com\/salesforce-cloud-services\/crm-development\/\">Integrated App development<\/a>, Custom App development and Technical Support business partners and end users. Salesforce Cloud CRM integration offered by Greytrix works with Lightning web components and supports standard opportunity workflow. Greytrix GUMU&#x2122; integration for Sage ERP \u2013 Salesforce is a 5-star rated app listed on <a href=\"https:\/\/appexchange.salesforce.com\/appxListingDetail?listingId=a0N30000000psM5EAI\" target=\"_blank\" rel=\"noopener\">Salesforce AppExchange<\/a>.<br> The GUMU&#x2122; Cloud framework by Greytrix forms the backbone of cloud integrations that are managed in real-time for processing and execution of application programs at the click of a button.<br><br> For more information on our Salesforce products and services, contact us at <a href=\"mailto:salesforce@greytrix.com\">salesforce@greytrix.com<\/a>. We will be glad to assist you.<\/p>\n\n\n\n<p><strong>Related Post:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.greytrix.com\/blogs\/salesforce\/tag\/apex-asynchronous-processing\/\" target=\"_blank\" rel=\"noreferrer noopener\">Smart Ways to Debug Salesforce Flows with Asynchronous Apex methods<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.greytrix.com\/blogs\/salesforce\/tag\/asynchronousprocessing\/\" target=\"_blank\" rel=\"noreferrer noopener\">How to Avoid Recursive Batch Execution in Salesforce Apex<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.greytrix.com\/blogs\/salesforce\/tag\/batch-apex\/\" target=\"_blank\" rel=\"noreferrer noopener\">Batch Processing in Salesforce<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Salesforce runs Apex in a multi-tenant environment, where multiple organizations share the same computing resources. To ensure fair resource usage and maintain platform performance, Salesforce enforces Governor Limits hard limits on database operations, CPU usage, and memory consumption. Some of the most important governor limits include: This is where Bulkification becomes essential. Bulkification is the\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.greytrix.com\/blogs\/salesforce\/2026\/07\/31\/how-to-write-bulkified-apex-code-in-salesforce-to-avoid-governor-limits\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[2318,3541,3554,3555,3255,3548,3549,2160,31,3550,3542,3545,3547,3553,3552,3543,2158,367,2467,588,3418,1709,3532,2463,2048,3083,392,2782,3421,397,2567,3544,3512,3546,3417,3551],"class_list":["post-13064","post","type-post","status-publish","format-standard","hentry","category-salesforce-srv","tag-apex-best-practices","tag-apex-bulkification","tag-apex-collections","tag-apex-maps","tag-apex-programming","tag-apex-trigger-best-practices","tag-apex-trigger-optimization","tag-asynchronous-apex","tag-batch-apex","tag-bulk-data-processing","tag-bulkification-in-apex","tag-bulkified-apex-code","tag-dml-best-practices","tag-dml-optimization","tag-future-methods","tag-governor-limit-safe-code","tag-queueable-apex","tag-salesforce","tag-salesforce-admin","tag-salesforce-apex","tag-salesforce-architecture","tag-salesforce-automation","tag-salesforce-code-optimization","tag-salesforce-coding-standards","tag-salesforce-crm","tag-salesforce-developer","tag-salesforce-development","tag-salesforce-development-best-practices","tag-salesforce-governor-limits","tag-salesforce-integration","tag-salesforce-performance","tag-salesforce-triggers","tag-salesforce-tutorial","tag-soql-best-practices","tag-soql-optimization","tag-trigger-framework"],"_links":{"self":[{"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/posts\/13064","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/comments?post=13064"}],"version-history":[{"count":17,"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/posts\/13064\/revisions"}],"predecessor-version":[{"id":13081,"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/posts\/13064\/revisions\/13081"}],"wp:attachment":[{"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/media?parent=13064"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/categories?post=13064"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.greytrix.com\/blogs\/salesforce\/wp-json\/wp\/v2\/tags?post=13064"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}