In complex Salesforce implementations, it's easy to bundle everything into a single metadata layer. This not only slows down development but also increases the risk of bugs, code conflicts, and deployment failures.
To address this, I recently came up with an initiative to redesign our Salesforce architecture around modular development, using unlocked packages, feature-based repositories, and aligning the internal code design with SOLID principles.
The results were immediate: better scalability, cleaner code, and faster team collaboration.
What is a Modular Structure in Salesforce?
A modular structure means organising your Salesforce codebase into independent, purpose-specific units. These units are implemented as unlocked packages—each one scoped to a specific domain or feature area like Opportunities, Cases, or Lead Conversion.
Example package breakdown:
- Core – Common utilities, shared layouts, reusable interfaces, and custom fields
- AccountManagement – Apex services, flows, Lightning Web Components (LWCs), and permission sets for Accounts
- CaseHandling – Case-specific flows, automation, and data logic
- LeadConversion – Lead-to-Opportunity conversion logic, subflows, and validation rules
Each package lives in its own Git repository and is treated as an independent SFDX project. Teams can develop, test, and deploy these modules separately.
Learn more: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_unlocked_pkg_whats_a_package.htm
Implementing a modular structure brings immediate benefits:
- Separation of concerns — Each package has a clear scope
- Independent pipelines — Smaller deployments and fewer conflicts
- Reusable components — Shared logic lives in Core, reused across modules
- Better team collaboration — Multiple teams can work in parallel
- Targeted testing — Easier to isolate and test business logic
- Improved CI/CD — Every module has its own validation and versioning process
Recommended read: CI/CD Best Practices for Unlocked Packages
https://developer.salesforce.com/blogs/2020/02/ci-cd-best-practices-for-unlocked-packages
Recommended Folder Structure (Per Module)
Each unlocked package follows the Salesforce DX source format. Here's a simplified structure we use for each module:
domain/ - Business logic and service classes
triggers/ - Trigger handlers
interfaces/ - Interfaces and abstract base classes
util/ - Utility/helper classes
All dependencies between packages (e.g., CaseHandling depends on Core) are managed via the sfdx-project.json file, making the system clean, explicit, and maintainable.
More on DX source structure: Salesforce DX Source Format Guide
https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_code_introduction.htm
CI/CD and Version Management
Each module has its own CI/CD pipeline that:
- Installs dependent packages (e.g., Core)
- Pushes only that module's metadata
- Creates and promotes package versions as needed
This ensures changes are well-tested, isolated, and can be deployed independently across environments.
If your Salesforce org is starting to feel tightly coupled or hard to manage, I highly recommend exploring a modular architecture with SOLID design principles.
This structure allows you to:
- Work at scale with multiple teams
- Build and test in isolation
- Release confidently with version control
- Maintain a clean, extensible code base