Code was written before anyone tried configuring it
A requirement gets handed to a developer and becomes Apex, when a work rule and a field would have done the same job and needed no maintenance at all.
Salesforce Field Service is highly configurable and genuinely extensible — and the difference between those two things decides your cost of ownership for the next decade. Twopir pushes configuration as far as it goes, then builds properly when it will not reach. We tell you when we are crossing that line, and what it costs.
Custom development is not the problem. Undocumented, untested, unnecessary custom development is. The cost shows up two years later, in the release that breaks everything.
A requirement gets handed to a developer and becomes Apex, when a work rule and a field would have done the same job and needed no maintenance at all.
It works fine when a dispatcher saves one record and fails the moment a maintenance plan generates four hundred work orders overnight — which is exactly when nobody is watching.
A bespoke "Job" object built alongside Work Order, because the standard object was not fully understood. Now every report, integration and upgrade has to handle both.
A Lightning Web Component that queries live data works perfectly in the browser and fails silently on a technician's phone in a basement. The bug is only ever found in the field.
Custom work assumes it can override scheduling behaviour that the package does not expose. The discovery happens after the estimate has been given and accepted.
Working code with no documentation, minimal test coverage and no explanation of why it exists. Nobody will touch it, so it constrains every decision from then on.
Configuration is cheaper to build, cheaper to maintain, and survives Salesforce releases more predictably than code. This is where the line genuinely sits, requirement by requirement — and it is the question almost no partner will answer plainly before a contract is signed.
| Requirement | Configuration or code | Why |
|---|---|---|
| Territories & Operating Hours | Configuration. Always. | Fully declarative, and anything custom here will fight the scheduling engine rather than help it. |
| Skills & Work Types | Configuration. | The standard model covers skill levels and requirements. Custom matching logic is almost always a sign the skill data is wrong. |
| Standard Work Rules | Configuration. | Match territory, required skill, availability, resource preference — the majority of real dispatch constraints are already expressible. |
| Unusual Scheduling Constraints | Custom work rule. | When a genuine constraint has no standard equivalent — a site that only accepts one specific crew, a regulatory pairing rule. |
| Work Order Process Automation | Configuration via Flow. | Record creation, field updates, notifications and escalation are Flow's core competence and your admin can maintain them. |
| High-Volume Record Processing | Apex. | Bulk generation, complex recalculation across thousands of records, or anything that will hit governor limits in Flow. |
| Dispatcher Console Layout | Configuration. | Gantt scope, list views, filters, policy choices and colour coding are all configurable — and usually never configured. |
| Custom Console Actions | Code. | Bespoke bulk operations or a panel the standard console does not offer. Check the package exposes the extension point first. |
| Mobile Data Capture | Configuration via mobile flows. | Conditional questions per work type cover most debrief requirements without a single component being written. |
| Custom Mobile Screens | LWC, built offline-first. | Only where a flow genuinely cannot express it. Must use offline-capable data access or it fails where the work is. |
| Extending The Data Model | Configuration. | Custom fields and related objects on the standard model. Replacing Work Order with a bespoke object is the expensive mistake. |
| External System Logic | Neither — integration. | If the logic belongs to another system, it belongs in the integration layer, not in Apex inside Salesforce. |
We produce this assessment for your specific requirement list during scoping, so the cost of each item is visible before anyone commits to it. See also Integration for anything that crosses a system boundary.
These are the three shapes of genuine Field Service development work, and what building each one responsibly actually involves.
Constraints the standard work rules cannot express. Built as custom work rules so they plug into the scheduling policy rather than fighting it from outside.
Logic on work orders, service appointments and assets that Flow cannot carry — usually because of volume, complexity or the need for careful error handling.
Custom screens for the console or the mobile app. On mobile these must be built offline-first, which is a different engineering problem from a desktop component.
It is a strange thing for a consultancy to optimise for, but every requirement we can meet declaratively is one you never have to maintain, test or upgrade around.
What is the underlying business need, and is the requested feature the only way to meet it? A surprising share of custom requests dissolve into a field and a work rule.
We prove the declarative route does not work rather than assuming it. That proof is part of the deliverable, so the decision to build is documented and defensible.
What the managed package exposes, what it does not, and how the extension stays safe across three releases a year. Decided before the first line is written.
Bulk-safe Apex and offline-first components, tested at realistic volume and peer-reviewed against Salesforce development standards.
What was built, why configuration could not do it, how to test it and what to watch at release time. The thing that is missing when a developer leaves.
The figures below come from one documented engagement with an HVAC services company running more than 100 field technicians across multiple regions. They describe that client's results — not an industry benchmark and not a Twopir average.
Field Service customized and integrated around an existing service operation.
The engagement customized and integrated Field Service around how the business already worked: the scheduling engine configured to assign on skills, location and availability, the mobile app deployed to technicians, inventory connected so parts were known before dispatch, and work orders generated automatically from incoming requests with SLAs attached. The work was configuration-led, which is why it held up as the operation scaled.
The engineering standards that decide whether custom work ages well.
If the logic belongs to another system, it belongs in the integration layer rather than in Apex inside Salesforce. This is the most common misplacement we correct.
Most process requirements that arrive described as customization are Flow work. Cheaper to build, and your own admin can change them later.
Custom mobile components carry an extra constraint: they must be built for offline or they fail in exactly the place a technician needs them.
Before commissioning custom scheduling logic, check the standard work rules and objectives genuinely cannot express the constraint. Usually they can.
Well-built customization does not, and that is largely a design decision rather than luck. Configuration is the most upgrade-safe option because Salesforce maintains the behaviour behind it. Custom code is safe when it uses documented extension points and does not depend on internal managed-package behaviour that was never guaranteed. The work that breaks is usually the work that reverse-engineered something undocumented because it was the quickest route at the time. We decide upgrade safety before building, and meaningful test coverage is what makes each release a check rather than a gamble.
Yes, through custom work rules that plug into the scheduling policy alongside the standard ones. The important part is that they sit inside the policy rather than trying to override the engine from outside, which keeps the behaviour explainable and lets the optimizer reason about them properly. Before building one, it is worth checking hard that the constraint is genuinely unexpressible — the standard rules cover more than most teams realise, and a custom rule runs against every candidate resource, so a poorly performing one slows every scheduling operation you have.
Extend the standard ones, in almost every case. Work Order, Service Appointment, Service Resource and Asset are wired into the scheduling engine, the dispatcher console, the mobile app and the reporting model. A custom object that duplicates one of them gets none of that for free and has to reimplement all of it. Custom fields and genuinely new related objects are fine and normal. The expensive mistake is building a bespoke "Job" object beside Work Order because the standard model was not fully understood — every report, integration and upgrade then has to handle both forever.
The package ships as managed code, which means its internals are not yours to modify — you extend it where it offers extension points and you work around it where it does not. In practice the scheduling and optimization behaviour is configurable to a considerable degree through policies, rules and objectives, and far less modifiable at the algorithm level. The practical consequence for scoping is that "can we make the optimizer do X" needs checking against the current package capabilities before anyone estimates it, rather than being assumed. We verify that during design rather than discovering it during build.
Build less of it, and document what you do build. The single biggest lever is refusing to write code for requirements that configuration can meet, because that code then needs testing, upgrading and explaining forever. After that it is ordinary engineering discipline: one trigger per object with explicit ordering, bulk-safe patterns throughout, test coverage that actually asserts behaviour rather than just reaching a percentage, and documentation that records why configuration was insufficient. That last point matters most — it is what lets the next person judge whether the custom work is still needed.
Yes, and it is a common starting point. A review covers what exists, whether it is bulk-safe, whether it will survive releases, where it duplicates standard functionality that could replace it, and what the realistic cost is of keeping it versus retiring it. We give you the honest answer including where the existing work is sound, because "rip it all out" is usually neither true nor affordable. The most valuable output is normally the list of custom components that can be retired in favour of configuration — that reduces your maintenance surface permanently rather than just tidying it.
We will tell you which items are configuration, which genuinely need code, and which belong in the integration layer instead — before anyone estimates the build.
Speak with a team that will tell you when not to build something