Customise around the package. A firm that cannot take an upgrade has bought a fork.
Litify ships releases. Every piece of custom work you add either survives them or quietly makes the next one harder, and the difference is architectural rather than a matter of care. We build the things the package does not do — custom objects, screens, logic and UI — in a way that leaves the vendor's upgrade path intact. Extend around it, never into it.
Upgrades Stay RoutineYour Work SurvivesOne Codebase
Architectural RuleExtend around · never modify what ships
0
Vendor components modified, on any engagement
200
Records every piece of Apex is tested against
12+
Years of Salesforce delivery
40+
Consultants, architects & developers
Trusted by 500+ organizations — including law firms and legal technology companies building their case, billing and reporting operations on Salesforce with Twopir Consulting.
Development Capability
Salesforce Partner
Apex
Lightning Web Components
Custom Objects
Screen Flows
Async & Batch
Test Coverage
Upgrade-Safe Design
How Customization Goes Wrong
Six ways custom work turns into technical debt
None of these are visible on the day they ship. They surface at the next vendor release, the next sandbox refresh, or the next time someone has to change the code — and by then the person who wrote it has gone.
Logic written to replace the package, not extend it
A custom matter object built because the standard one was inconvenient. Now every Litify feature, every integration and every vendor improvement bypasses your firm entirely, and you maintain a parallel product.
Hard dependencies on package internals
Apex referencing package fields by assumed API name, or logic that depends on how the vendor currently implements something. It works until the release where they change it, and the failure is opaque.
Code that was never bulk-tested
An Apex trigger that works on a single record and fails on a data load. It passes every manual test, then takes out a migration or a mass billing run — the two moments when failure is least affordable.
Custom UI rebuilt from scratch
A Lightning Web Component that reimplements what a record page and a Screen Flow would have done. More code, more maintenance, no more capability, and one more thing to retest on every release.
No tests worth the name
Coverage achieved by asserting nothing. It satisfies the deployment gate and tells you nothing about whether the code works, which you discover the first time somebody changes it.
One person understood it, and they left
Undocumented custom work is a liability whoever wrote it. The firm ends up afraid to touch a component that nobody can explain, and eventually pays to rebuild something that was working.
The Governing Constraint
Litify is a managed package. That decides everything.
A managed package is code and configuration installed into your org and owned by the vendor, sitting in its own namespace. You cannot edit what is inside it, and you should not want to: the namespace boundary is exactly what lets Litify ship a release into thousands of orgs without breaking them. Customising Litify therefore always means building alongside the package, in your own namespace, using the platform's extension points.
Those extension points are generous. You can add custom objects that relate to Litify's. You can add custom fields to package objects where the vendor allows it. You can write Apex that operates on package data, build Lightning Web Components that appear on package record pages, add Flows, validation rules, page layouts and permission sets. Almost anything a firm actually needs is reachable without touching a vendor component.
The discipline is knowing where the line is and staying behind it, even when crossing it would be quicker this week. Custom work that depends on package internals — an assumed API name, an implementation detail, a field the vendor might repurpose — is the debt that surfaces at the worst moment. We write defensively for that reason, and we verify the real object and field names in your org rather than trusting public sources, which disagree with each other.
Custom Objects
New objects related to Litify's, for data the package has no home for.
Lightning Web Components
Screens and interactions the package does not provide, on its record pages or your own.
Apex
Logic that has to run at volume or express rules Flow cannot, bulk-safe and tested.
Screen Flows
Guided multi-step processes, built declaratively wherever an LWC would be overkill.
Custom UI
Consoles, calculators and views designed around a task rather than around a record.
Experience Cloud
Client and referral-partner portals built on Litify data with the sharing model respected.
Test Coverage
Tests that assert real behaviour under bulk, not coverage achieved by asserting nothing.
Upgrade Safety
A release check in a sandbox before every Litify version reaches production.
Before You Build
Three questions we ask before writing any code
Most customization requests have a cheaper answer than the one they arrived with. We work through these in order, and we are genuinely happy to conclude that no code is needed.
Question 01 · Necessity
Can configuration already do this?
The answer is yes more often than firms expect. A well-built matter plan, a Screen Flow and a good page layout reach a long way, and every piece of code avoided is one less thing to maintain and retest.
What the package already does, checked properly
What a Screen Flow would cover
What a page layout or dynamic form solves
Whether a validation rule is the real answer
Whether an AppExchange app already exists
The honest cost of building versus configuring
Outcome Frequently: no code. We would rather tell you that in a scoping call than bill for a component you did not need.
Question 02 · Placement
Where does it sit relative to the package?
Alongside, always — but the detail matters. A custom object related to Matter behaves very differently from one that duplicates it, and the choice is hard to reverse later.
Custom object versus custom fields on the package
Relationship design and sharing implications
Whether reporting will still work across both
Effect on existing integrations
What a package upgrade could touch
Migration path if the vendor ships it later
Outcome A placement decision with its reasoning recorded — including what happens if Litify ships this capability natively in a future release.
Question 03 · Longevity
Who maintains this in two years?
Custom work is a permanent commitment. If your team cannot maintain it and you do not want a permanent retainer, that changes what we should build and how.
Your team's Salesforce capability, honestly assessed
Documentation and handover expectations
Test coverage sufficient for safe change
How configuration-driven it should be
Release testing responsibility
What happens when requirements change
Outcome A build shaped around who owns it. Sometimes that means more configuration and less code, deliberately, even though it takes longer to build.
Scroll the table sideways →
Which tool to use for which Litify customization job, and why the obvious alternative is worse
What you want
What it should be built with
Type
A field the package does not have
A custom field on the package object where the vendor permits it, otherwise on a related custom object.
Configuration
A guided multi-step process for staff
A Screen Flow. Declarative, maintainable by an admin, and no code to retest on every release.
Configuration
Data the package has no home for
A custom object related to Matter or Intake — never a replacement for either of them.
Custom object
A purpose-built console or calculator
A Lightning Web Component, with Apex behind it only where it must query or write at volume.
LWC
Logic across thousands of records
Apex, batched and bulk-safe, with tests that assert real behaviour rather than chasing coverage.
Apex
A client or referral-partner portal
Experience Cloud over Litify data, with the org sharing model enforced rather than reimplemented.
Experience Cloud
What We Build
Six kinds of custom work, and when each is justified
Every one of these is something the package does not do. If a request can be met by configuration, it does not belong on this list and we will say so.
Custom Objects & Data Model
For data Litify has no home for — a referral fee structure, a lien tracker, a practice-specific record. Related to the package objects, never replacing them.
Object and relationship design
Sharing and visibility inherited properly
Reporting across custom and package data
Effect on existing integrations assessed
Migration path if Litify ships it natively
Naming that will still make sense later
Lightning Web Components
Where the interaction is genuinely richer than a record page or Screen Flow can express — an intake console, a settlement calculator, a triage board.
Component design against a real task
Apex behind it only where volume demands
Placed on package record pages where useful
Accessible and keyboard-navigable
Jest tests alongside Apex tests
Styled to the org, not to a framework default
Apex Development
Logic that must run at volume or express rules configuration cannot. Written to the platform's standards because the standards exist for good reasons.
Bulkified to 200 records as a baseline
No SOQL or DML inside loops, enforced in review
Queueable and Batch for async work
Selective queries against indexed fields
Tests that assert behaviour, not coverage
Defensive against package field changes
Screen Flows & Guided Processes
Declarative first. A Screen Flow your admin can change beats a component only we can change, and it survives releases with less testing.
Multi-step intake and triage screens
Conditional paths by case type
Reusable sub-flows for common steps
Error handling and fault paths
Built for admin maintainability
Documented for the person who inherits it
Portals & External Experiences
Client and referral-partner access to matter data, built on Experience Cloud so the org's sharing model is enforced rather than reimplemented in application code.
Experience Cloud site over Litify data
Sharing model enforced, never bypassed
Document upload into the matter
Status visibility without internal detail
Authentication and identity design
Mobile-usable, because clients are on phones
Technical Debt Remediation
Inherited custom work that nobody can safely change. We make it explicable before we make it better.
Inventory with ownership and last-modified
What is load-bearing versus what is dead
Test coverage added before refactoring
Package dependencies identified and removed
Safe retirement of unused components
Documentation so it stops being a liability
Upgrade Safety Rules
Six rules that keep vendor releases routine
These are the difference between a Litify upgrade being a sandbox check and a Litify upgrade being a project. Each one exists because its absence has cost somebody a weekend.
Rule 01
Never Modify What The Vendor Ships
The namespace boundary exists for a reason and we stay behind it, without exception. Anything that would require editing a package component is redesigned rather than forced.
Protects The entire upgrade path. One modified vendor component is the difference between an upgrade and a migration. Rule 02
Verify API Names In The Org
Public sources disagree on Litify's namespace and custom API names, and the authoritative reference sits behind a customer login. We query the org and work from what it reports.
Protects Against code that compiles against an assumed field name and fails in an org where it is different. Rule 03
Depend On Data, Not Implementation
Custom logic reads package data through supported interfaces. It does not rely on how the vendor currently implements something internally, because that is theirs to change.
Protects Against the release where an internal detail changes and your logic fails in a way nobody can trace. Rule 04
Configuration In Metadata
Thresholds, mappings and rules live in custom metadata records rather than hard-coded. Behaviour changes without a deployment, and without a developer.
Protects Against a change queue for values the business should be able to edit itself on a Tuesday. Rule 05
Tests That Assert Behaviour
Real assertions under bulk conditions, not coverage achieved by exercising code and checking nothing. The test suite is what makes the next change safe.
Protects Everyone who touches the code after us — including your own team, which is the point. Rule 06
Release-Check Every Version
Litify releases go into a sandbox first and custom components are exercised against them before production. A routine check, scheduled, rather than a discovery after the fact.
Protects Against finding out that a release broke something from a user on a Monday morning.
How We Deliver
Five phases, and the first one often ends the project
We start by trying not to build. It is the cheapest phase and it regularly saves firms more than the rest of the engagement costs.
Phase 01
Challenge The Requirement
What the package already does, what a Screen Flow would cover, whether an AppExchange app exists. A genuine attempt to avoid writing code, because code is a permanent commitment.
Phase 02
Verify The Org
Real object and field names, package version, existing custom components and their dependencies. Public sources on Litify API names are unreliable; your org is authoritative.
Phase 03
Design For Upgrade
Placement relative to the package, sharing and reporting implications, what a future vendor release could touch, and the migration path if Litify ships the capability natively.
Phase 04
Build & Test
Built to platform standards, bulk-tested to 200 records, with tests that assert behaviour. Code review on every change, against the rules above.
Phase 05
Document & Hand Over
Documentation your team can act on, a release-check procedure, and enough test coverage that the next person can change it safely without us.
Why we try to talk you out of it first Custom code is a permanent commitment: it has to be maintained, retested on every vendor release, and understood by whoever inherits it. Configuration carries almost none of that weight. We routinely find that a request arriving as "we need a custom component" is met by a Screen Flow, a dynamic form and a validation rule — and we would rather establish that in a scoping call than bill for something you will still be maintaining in 2029.
When Code Is The Answer
Four situations configuration genuinely cannot reach
These are the cases where we stop trying to avoid code. Everything else deserves one more attempt at a declarative answer first.
Volume Beyond Flow
Logic that has to run across thousands of records. Flow hits limits here and fails in ways users see; this is what Batch and Queueable Apex exist for.
A Screen That Is Not A Record Page
An intake console, a settlement calculator, a triage board. When the interaction is organised around a task rather than a record, a component earns its place.
Data With No Home
Lien tracking, referral fee structures, practice-specific records. A custom object related to Matter, never a replacement for it.
External Users
Clients and referral partners needing access to matter data. Experience Cloud over Litify, with the sharing model enforced rather than reimplemented.
Client Outcomes
Legal platforms we have actually built
Two engagements from our legal practice. Both involved custom Salesforce development around packaged applications — built so the packages underneath could still be upgraded.
OL★★★★★
Twopir provided Salesforce customisation and integration services to help us build a robust,
compliant, and scalable legal operations platform — connecting case management, document
processing, and financial systems into one unified workflow. The result was transformative
for how we run case-to-cash operations.
Operations LeadFast-growing personal injury law firmPersonal Injury
Case Study
Personal Injury Firm — Multi-State
Streamlining case-to-cash operations with Salesforce, AWS and QuickBooks.
Twopir's specialized Salesforce customization enabled efficient integration of third-party
systems and streamlined administration and billing, leading to seamless financial operations
and enhanced productivity. Automated mass billing and matter management minimized errors
across our entire legal workflow.
Practice ManagerMid-size US family law firm · 150 employeesFamily Law
Case Study
Family Law Firm — 150 Employees, US
A 50% efficiency gain from Accounting Seed and Salesforce integration.
The measure of good custom development is whether the next person can safely modify it. Most inherited Salesforce code fails that test, and the firm pays for it twice.
01
We try not to build first
Configuration reaches further than most firms expect, and every piece of code avoided is one less thing to maintain and retest on every vendor release. We are happy to end a scoping call by recommending a Screen Flow.
02
We extend around the package, never into it
Custom objects, Apex, Flow and Lightning Web Components built so the vendor's next release upgrades cleanly. A firm that cannot take a Litify upgrade has bought a fork, not a platform.
03
We verify your org instead of assuming it
Litify's object and field reference sits behind a customer login, and public sources disagree on details as basic as the namespace prefix. We confirm the real objects, fields and package version in your org in week one — and we say so rather than quoting from a blog post.
04
Tests that assert behaviour, not coverage
Coverage achieved by asserting nothing satisfies the deployment gate and tells you nothing. Our tests assert real behaviour under bulk conditions, because the test suite is what makes the next change safe.
05
We document for the person who inherits it
Custom work only one person understands is a liability whoever wrote it. Documentation and handover are part of the build, not an optional extra we quote separately.
Go Deeper
The rest of our Litify practice
This page covers one service. Each one below goes into the detail a specific team needs — pick the one closest to the question you arrived with.
It can be customised extensively — you simply do it alongside the package rather than inside it. A managed package sits in the vendor's own namespace and its components cannot be edited, which is precisely what allows Litify to ship releases into thousands of orgs without breaking them. But you can add custom objects related to Litify's, add custom fields to package objects where the vendor permits, write Apex that operates on package data, build Lightning Web Components that appear on package record pages, and add Flows, validation rules, layouts and permission sets. Almost anything a firm actually needs is reachable without touching a vendor component.
Not if it is built correctly, and this is the single most important thing to get right. Custom work that lives in your own namespace and depends only on supported interfaces upgrades cleanly. Custom work that depends on package internals — an assumed API name, an implementation detail, a field the vendor might repurpose — is the debt that surfaces at the worst possible moment. We write defensively, verify the real object and field names in your org rather than trusting public sources, keep configuration in custom metadata, and run a release check against each Litify version in a sandbox before it reaches production.
Four situations genuinely justify code. Logic that must run across thousands of records, where Flow hits governor limits and fails visibly. A screen organised around a task rather than a record — an intake console, a settlement calculator. Data the package has no home for, which needs a custom object related to Matter rather than a replacement for it. And external users needing access, which means Experience Cloud. Everything else deserves another attempt at a declarative answer first, and we will make that attempt before quoting for a build.
Yes, and the sequence matters. We inventory what exists with ownership and last-modified dates, establish what is load-bearing versus what is dead, and add test coverage before refactoring anything — because changing untested inherited code is how a working system becomes a broken one. We identify and remove hard dependencies on package internals, retire unused components safely, and document what remains. The goal is that your team stops being afraid to touch it, which is usually the real problem.
Yes, on Experience Cloud over Litify data. The critical design principle is that the sharing model is enforced rather than reimplemented: a portal that queries data with elevated permissions and filters in application code is one bug away from showing a client someone else's matter. Built properly, external users see exactly what the org's sharing rules permit. Typical scope covers matter status visibility, document upload into the matter, secure messaging and online payments, and it has to work on a phone because that is where clients are.
The platform's own, because they exist for good reasons. Bulkified to 200 records as a baseline and tested at that volume. No SOQL or DML inside loops, enforced at code review. Queueable and Batch for asynchronous work rather than blocking a user transaction. Selective queries against indexed fields. Configuration in custom metadata rather than hard-coded, including no literal record type or Case Type IDs. And tests that assert real behaviour under bulk conditions, not coverage achieved by exercising code and checking nothing.
Workflow and automation covers declarative work inside the org — matter plans, Salesforce Flow, validation rules, assignment and escalation logic. This page covers what happens when those genuinely cannot reach: custom objects, Lightning Web Components, Apex that is not integration code, and portals. There is real overlap at the boundary, which is why both pages say the same thing about it — configure first, code only where configuration cannot reach. If you are not sure which side of the line you are on, that is a scoping conversation and usually a short one.
Next Step
Tell us what you want to build — we will start by trying to avoid building it
A technical scoping conversation covers what you need, whether configuration already reaches it, and if not, how it should be placed relative to the package so upgrades stay routine.