A Step-by-Step Guide to Refactoring a God Trigger in Salesforce
By Kodelens Team
•July 20, 2025

Every seasoned Salesforce developer knows it. It has a name spoken in hushed, fearful tones during sprint planning: the AccountTrigger, the OpportunityTrigger, the CaseTrigger.
It's a single Apex file, thousands of lines long, handling dozens of unrelated tasks from field validations to integration callouts. It's a "God Trigger," a monolithic beast that holds your org's core logic hostage. And you've just been assigned the task of taming it.
God Triggers are the heart of technical debt. They are impossible to test reliably, terrifying to modify, and a direct cause of production bugs and slow performance.
Refactoring one feels like performing open-heart surgery on your org. But it's not impossible. With a clear, step-by-step plan, you can methodically dismantle the monolith and replace it with a clean, scalable, and maintainable framework. This guide will show you how.
The Goal: A Modern Trigger Handler Framework
Before we start surgery, let's define what a healthy heart looks like. Our goal is to implement a modern Apex trigger handler pattern.
- One Trigger Per Object: Your object (e.g.,
Account) will have a single Apex trigger. That's it. - Logic-less Trigger: This trigger will contain zero business logic. Its only job is to check the execution context (
Trigger.isBefore,Trigger.isUpdate, etc.) and delegate immediately to a handler class. - The Handler Class: A separate Apex class (
AccountTriggerHandler.cls) will contain the actual business logic. It will have specific methods for each context (e.g.,handleAfterUpdate(List<Account> newAccounts, Map<Id, Account> oldAccountMap)). - Separation of Concerns: The handler then calls other, more specific service or domain classes to do the work. This keeps your code organized, reusable, and easy to test.
Step 0: De-Risking - The Preparation Phase
This is the most important step. Do not touch the production trigger code yet. Your prime directive is: do no harm.
Action 1: Build Your Safety Net (Full Test Coverage)
Before you change a single line, you must ensure the existing God Trigger has the highest possible test coverage. Write new Apex tests if you have to. These tests are your safety net. They are the objective proof that your final, refactored code still performs all the same functions as the old code. If your new code passes the old tests, you haven't broken anything.
Action 2: Map Every Piece of Logic
This is where the real work begins. You cannot refactor what you do not understand. You must map out every distinct business process hidden inside that trigger.
- The Old Way: Manually read all 2,000+ lines, try to draw sequence diagrams on a whiteboard, and pray you don't miss a critical
else ifblock hidden in a nested loop. This is slow and prone to error. - The Smart Way: Use an intelligent code discovery tool to accelerate this process. With a semantic search tool like Kodelens, you can ask your codebase direct questions and get immediate answers. Run queries like:
"Find all callouts in this trigger""Show me where the Billing Address is updated""Where is the logic for creating child Contact records?"
This turns days of manual archeology into a few hours of targeted analysis. The output should be a simple document listing every distinct piece of business logic the trigger performs.
Step 1: The Bypass - Create the New Framework
Now we build the new house next to the old one, with a door between them.
- Create the Handler Class: Build your new, empty
AccountTriggerHandler.clswith all the necessary methods (beforeInsert,afterUpdate, etc.). - Create a Bypass Permission: Create a new Custom Permission called
Execute_Legacy_Account_Trigger. This will be your master on/off switch. - Install the Guard Clause: In the very first line of your old God Trigger, add a guard clause:
if (!FeatureManagement.checkPermission('Execute_Legacy_Account_Trigger')) { return; } - Deploy: Deploy the empty handler and the modified God Trigger. At this point, nothing has changed functionally. Everyone has the custom permission by default, and the old trigger runs as it always has.
Step 2: The Migration - Move Logic Incrementally
This is the core of the process. Do not try to move everything at once.
- Choose One Piece of Logic: Look at your map from Step 0 and pick the simplest, most isolated function (e.g., a single field validation rule).
- Move and Adapt: Copy that logic from the old trigger into the correct method in your new
AccountTriggerHandler. While you're at it, clean it up. Bulkify it properly and apply modern best practices. - Write a New, Targeted Test: Write a specific unit test for only this piece of logic in your new handler. This test should fail if you run it on its own.
- Deploy and Test: Deploy the updated handler and the new test. Now, create a Permission Set that revokes the
Execute_Legacy_Account_Triggerpermission and assign it only to your user. When you test in the UI, your user will bypass the old trigger and execute your new handler. Confirm your single piece of logic works, and that the rest of the trigger's functionality does not run for you.
Step 3: The Rinse and Repeat Cycle
Now, you simply repeat the incremental process from Step 2 for every piece of business logic on your map.
- Choose the next piece of logic.
- Move it from the old trigger to the new handler.
- Write a new, targeted test for it.
- Deploy and validate.
This incremental cycle is incredibly safe. If you introduce a bug, you know it's in the small piece of code you just moved. You can easily comment it out or roll it back without affecting the dozens of other functions still running safely in the legacy trigger.
Step 4: The Decommissioning
Eventually, you will have moved the last piece of logic out of the God Trigger. The old trigger is now an empty shell, containing only the guard clause. The glorious final moment has arrived.
- Run All Tests: In your sandbox, run everything—the original safety net tests from Step 0 and all of your new, granular tests. They must all pass.
- Remove the Permission: Remove the
Execute_Legacy_Account_Triggerpermission from all users. Now everyone is using the new handler framework. - Monitor: Let the new code run in production for a week or a full business cycle to ensure everything is stable.
- Deactivate and Delete: Once confident, deactivate the old God Trigger in production. After a final grace period, delete the Apex class forever.
You've done it. You have successfully slain the beast and replaced it with a clean, maintainable, and scalable system that will serve your organization for years to come.
Conclusion: From Fear to Confidence
Refactoring a God Trigger is a marathon, not a sprint. It requires patience, discipline, and a solid plan. By preparing properly, using intelligent tools to map the logic, and migrating functionality piece by piece, you can transform a high-risk, high-anxiety task into a manageable and safe engineering project.
Don't let technical debt hold your org hostage. Take the first step today by mapping out your most problematic trigger. See what's really inside it, and build your plan for a better, cleaner future.

