The choice between configuration and custom code is often treated as a matter of preference. In practice, it is a cost decision, especially when you look beyond the initial build.
A declarative solution may take a few days to build and can usually be maintained by an administrator. Custom code costs more to develop, but the expense does not end when the code goes live. Tests need to be maintained, Salesforce releases need to be checked for regressions, governor limits need to be considered as data volumes grow, and someone needs to understand how the code works when the original developer is no longer around.
That does not make Salesforce custom development a bad choice. It means there should be a clear reason for using it.
What a Line of Apex Actually Costs
Look at the full life of the code rather than just the development estimate, and the calculation changes.
The initial build is often the smallest part of the cost. Every Apex class needs meaningful test coverage, and those tests need to be updated when the underlying logic changes. Salesforce also has three major releases each year, so custom behavior needs to be checked as the platform evolves. Even when nothing breaks, that still creates testing and regression work.
Data volume creates another cost that may not show up for months or years. Code that works well with a few thousand records can behave very differently when it has to handle a few million. Governor limits can turn an implementation that once worked well into a performance problem or an incident. By then, the person who wrote the code may no longer be with the company.
Then there is the knowledge cost.
Custom logic is usually easiest to understand for the person who wrote it. Without good documentation, it becomes much harder for another developer or administrator to maintain. Documentation quality across custom Salesforce work can vary considerably. Every undocumented class adds friction to future changes involving the objects and processes it touches.
The answer is not to avoid code. It is to be more deliberate about where code is worth the long-term cost.
Where Configuration Wins Outright
Some requirements rarely need custom development. Recognizing them early can save a significant amount of time and maintenance work.
Standard business objects and their relationships should generally be handled through the Salesforce data model rather than custom code. Approval processes are another example. Even complex approval paths are often better handled declaratively because they may change as reporting structures and organizational responsibilities change.
The same principle applies to field validation. A validation rule that an administrator can read and update is easier to maintain than custom code for the same requirement.
Screen flows have also replaced many custom interfaces that would once have required development. They can support guided processes while allowing administrators to make changes without deploying code. Notifications, assignment rules, and record-triggered updates generally fall into the same category.
The important question is not whether custom code could produce a better result in isolation. It often can. The real question is whether that improvement justifies creating something that may require a developer every time it needs to be changed over the next five years.
When Salesforce Custom Development Actually Wins
There are four situations where custom code has a strong case. The most convincing requirements usually meet more than one of them.
1. The logic is genuinely proprietary.
If a pricing algorithm, risk model, or allocation method gives the business a competitive advantage, custom code may be appropriate. Trying to express proprietary logic entirely through declarative tools can result in a partial or overly complicated implementation.
2. You have reached a documented limit of declarative tooling.
Some requirements simply go beyond what declarative tools can handle effectively. Examples include complex multi-object transactions that require rollback, high-volume batch processing, and callout orchestration that needs retry logic.
The important point is that the limit should be real and documented. "Code would be cleaner" is not the same thing.
3. The requirement is likely to remain in place.
Logic tied to a regulation, contract, or industry standard is more likely to remain relevant through several rounds of process changes. That makes the investment in custom development easier to justify.
4. Performance is a defined requirement.
If a process has to complete within a specific time window while handling a certain volume of data, the way declarative automation executes may become a constraint. In that situation, custom development can provide the control needed to meet the requirement.
There is also a common reason for writing code that should be treated as a warning rather than a justification: the declarative solution feels inelegant.
Elegance is not a business case. Once that code is in production, it becomes another asset that someone has to maintain.
A simple rule can help at the start of the process. Every request for custom development should state which of these four conditions it meets and explain why configuration is not sufficient. If the request cannot answer those questions clearly, configuration is usually the better place to start.
Salesforce Custom Application Development On and Off the Platform
Once a requirement grows beyond a straightforward extension, there is another decision to make. Should the Salesforce custom application development happen within Salesforce or outside the platform?
Building on Salesforce keeps the data model, sharing model, and identity in one place. It also allows the application to use the platform's existing security and audit capabilities. That makes an on-platform approach useful for applications that work directly with customer records and explains why many internal tools are better suited to the platform.
There are cases where building beside Salesforce makes more sense. An external application can be appropriate when the workload involves heavy computation that could put pressure on platform limits, requires specialized libraries that Salesforce does not provide, serves users who do not have Salesforce licenses, or has a cost profile that does not work well with platform pricing.
One problem deserves particular attention when taking this approach: rebuilding Salesforce's sharing model in the external application.
Access rules that are copied into another system can quickly diverge from the source. That creates both maintenance and audit problems. If an external application needs to make record-level access decisions, it should rely on Salesforce for those decisions rather than maintaining a separate version of the access logic.
There is also some confusion around terms such as application, cloud, and module. A custom cloud in Salesforce generally refers to a group of custom objects, tabs, and interfaces built around a particular business function. The label matters less than how the functionality is managed.
Every custom application should have an owner, a version, and a retirement path. Those three things have a direct impact on what it costs to maintain over time.
Packaging also matters when the same functionality is used across multiple business units. A Salesforce custom app built as an unmanaged collection of metadata can drift between Salesforce orgs. Packaging it with a namespace and version gives teams a more consistent way to manage and compare the functionality.
AI Assistance Changed the Volume, Not the Ownership Cost
AI has made it possible to produce code much faster. The harder question is whether teams can review and maintain that code at the same pace.
Stack Overflow's developer research reports that 84% of developers use or plan to use AI tools, while trust in their accuracy fell to 29%, down eleven percentage points year over year. Developers also reported that output that is almost correct is a common source of frustration, particularly when debugging takes longer than expected.
For Salesforce custom app development, this creates three practical concerns.
First, review capacity can become the bottleneck. If a team doubles its coding output without increasing the amount of review it performs, it may ship more code while having less understanding of what that code actually does.
Second, test quality becomes more important. Generated tests can meet coverage requirements without testing the behavior that matters. Coverage percentage was never a complete measure of test quality, and it becomes even less useful when tests can be generated quickly.
Third, Salesforce-specific constraints need to be checked deliberately. Generated Apex can be syntactically correct while still handling bulkification, sharing enforcement, or governor limits poorly. These are platform-specific concerns that require someone familiar with Salesforce to review the implementation.
Security needs the same attention.
The broader point is simple: AI has reduced the cost of writing code, but it has not reduced the cost of owning it.
If anything, faster code generation makes disciplined development more important because teams can now create custom functionality faster than they can properly review and maintain it.
Instrument Everything You Build
Custom functionality that nobody measures becomes difficult to retire. Over time, that can make a Salesforce org harder and more expensive to change.
Usage should therefore be part of the design from the beginning. Every custom component should record basic information such as how often it is used, how many distinct users rely on it, and when it was last used. The information should be stored somewhere it can be queried later.
That small investment makes future decisions much easier. Instead of arguing about whether a component is still needed, the team can look at its actual usage.
Three practices make this information more useful.
First, assign every custom component a named business owner and record that ownership in metadata. Do not rely on someone remembering who owns it.
Second, set a review date when the component is created. This makes review part of its normal lifecycle instead of something the team has to remember years later.
Third, record why the custom functionality was built in the first place. The question a few years from now will not simply be "What does this code do?" It will be "Why did we need this code?" The original reason may no longer be obvious.
This becomes particularly important as AI agents begin interacting with enterprise applications.
The Migration Path Between the Two
The decision between configuration and code does not have to be permanent.
Salesforce continues to add capabilities that can replace custom functionality. Screen flows, record-triggered automation, and dynamic forms have already taken over areas that previously required custom development.
That creates a simple opportunity during each Salesforce release: look at older custom components and ask whether they are still necessary.
Most teams do not do this regularly because retiring code does not create a visible new feature. It also introduces some regression risk. As a result, old customizations tend to stay in place long after their original purpose has disappeared.
A better approach is to make the review routine.
Once a year, identify custom components that were originally created because of a limitation in declarative tooling. Check whether that limitation still exists. Choose the clearest two or three candidates, test the replacement properly, and retire the old components.
The reverse can happen, too.
A declarative solution can become so complicated that it starts to resemble custom code. A flow with twenty steps, nested subflows, and undocumented branches may technically be declarative, but that does not automatically make it easier to maintain.
A useful warning sign is whether a new administrator can understand the flow in fifteen minutes. If they cannot, it may be time to reconsider the design and determine whether the four conditions for custom development now apply.
A Build Standard Worth Adopting
The easiest way to prevent unnecessary custom development is to establish the rule before work begins.
A practical standard can be built around five principles.
Configuration is the default.
Custom development requires a clearly stated reason based on one of the four conditions discussed above.
Every custom component needs meaningful tests, documentation that explains the intent behind the logic, usage instrumentation, and a named owner.
Unused custom components should automatically enter a retirement review after a defined period.
Finally, any change involving an object that already has custom logic should include a review of that existing logic.
The standard should be applied during estimation, not during a cleanup exercise years later. If a request cannot answer the required questions, it should not move forward to estimation until those questions are resolved.
That may add ten minutes to the process today. It can save much more time later, when the people who understood the original implementation are no longer available.
The same standard should apply to Salesforce custom cloud application development delivered by external teams. It should also be reflected in the contract.
Instrumentation and ownership metadata should be defined as deliverables rather than left as recommended practices. Under deadline pressure, recommended practices are often the first things to disappear.
Salesforce custom development makes sense when the logic is proprietary, the declarative limit is real, the requirement is durable, or performance is a defined requirement. In other situations, the long-term maintenance cost often makes configuration the more practical option.
Sign in to leave a comment.