Development

7 min read

Broadleaf Fundamentals: A Developer's Guide to Domain Extensibility

Chris Kittrell

Written by Chris Kittrell

Published on Sep 19, 2025

Developer Working

Understanding Broadleaf's core architectural principles is key to building successful extensions. The platform is designed for deep customization, and a grasp of its foundational concepts, from domain separation to data tracking, is essential for any developer looking to extend or integrate with it. This guide covers the fundamental ideas that underpin all Broadleaf domains, providing the groundwork for your custom development.

Introduction: Why These Fundamentals Matter

When building upon a robust, extensible platform like Broadleaf, it’s important to have a strong understanding of the foundational building blocks that the framework provides. Working to master Broadleaf’s extensible domain concepts is a great pace to start! This will allow you to effectively expand upon the out-of-box domain representations and build your own domain that is similarly scoped to a specific tenant, application, or customer context.

The Two-Tiered Domain Architecture: Projection vs. Persistence

A core concept for Broadleaf domain is the separation of concerns between projection and persistence domains. At a high level:

  • Projection Domain (Business Domain): This is the Data Transfer Object (DTO) representation. It's the data model exposed to external API callers, and it's what gets serialized to and from JSON. This representation is clean, contains only what's necessary for the client, and can be transformed from the raw data.
  • Persistence Domain (JPA Representation): This is the JPA entity that corresponds directly to a table in the database. It may contain internal-facing fields, and its structure is optimized for database storage and queries, not for external consumption.

This separation provides crucial flexibility. It ensures that internal implementation details of the database model are not exposed to the outside world, and it allows for a transformed representation of data to be presented to API callers.

Note: In many cases, you may see projection domains by the same name in different services, but each class includes a different set of fields. These are examples of projection domains only deserializing the portions of the JSON payload that they care about.

Mapping with ModelMapper

To handle the transformation between these two representations, Broadleaf uses ModelMapper. This powerful library automates most of the mapping process. Instead of manually writing boilerplate code to copy every field from one object to another, ModelMapper can automatically map fields with the same name and type.

The ModelMapperMappable interface is a Broadleaf-specific contract for this process. Persistence domain classes that implement this interface define two key methods:

  • fromMe(): Defines the mapping from the persistence domain to the projection domain.
  • toMe(): Defines the mapping from the projection domain to the persistence domain.

When you extend Broadleaf, the platform’s mapping pipeline automatically invokes these methods during typical CRUD (Create, Read, Update, Delete) operations, significantly reducing the amount of code you need to write.

TypeFactory: A Central Registry for Extensibility

When you extend a Broadleaf class, you need a mechanism to ensure your custom class is used everywhere the base class would be. That’s where TypeFactory comes in. It's a centralized registry that understands the relationship between base Broadleaf types and your custom, extended types.

TypeFactory ensures that:

  • When a JSON request body is deserialized, it's automatically converted into an instance of your extended class.
  • When the framework needs to manually instantiate an object, it uses TypeFactory to get an instance of your extended type.

This component is ubiquitously integrated into the framework, so in most cases, you don’t need to interact with it directly. However, it's important to understand that it's the reason your extensions just work out of the box without requiring you to change any of the core Broadleaf endpoint or object instantiation code.

Note: In rare cases where auto-detection fails, you can explicitly register your custom type using a TypeSupplier bean.

Data Tracking: Context-Awareness and Workflows

Broadleaf's data tracking facility is a powerful feature that underpins multi-tenancy, sandbox environments, and workflow approvals. It's the system responsible for ensuring that a request only sees the appropriate data for its specific context.

  • ContextInfo: Every API request is expected to include a special header called ContextRequest. This header contains details about the tenant ID, sandbox ID, and application ID. The backend resolves this into a ContextInfo object, which is passed down to service and repository components. This object serves as the blueprint for filtering data.
  • Trackable Interface: Any entity that needs to be discriminated by context must implement the Trackable interface. This is a marker interface that signals to the framework that this entity participates in data tracking behaviors.
  • Narrowing & Transition: Narrowing is the filtering mechanism that uses the ContextInfo to ensure a request only receives data relevant to the requested context. For example, a request from "Application 2" will only see products assigned to "Application 2". Transition refers to the mechanisms that manage data as it moves through a sandbox approval lifecycle (e.g., from a user's sandbox to a "promoted" or "approved" state).
  • Context ID: In scenarios where multiple versions of a single logical entity exist (e.g., a product in a production state vs a modified version in a user's sandbox), the contextId is used to uniquely identify the logical entity across all of its physical records. The physical database primary key is a separate, globally unique ID.

For most extensions, you simply need to ensure your entity is marked with the appropriate trackable interface and tracking configuration; the framework handles the rest of the heavy lifting.

RSQL: Powerful, Flexible Filtering

Broadleaf supports Rest Query Language (RSQL), which allows API callers to specify arbitrary filters in a request to limit the results. This is a powerful tool for developers because it minimizes the need to create custom endpoints for every possible query.

An RSQL filter string is passed in the “cq” parameter of a request. The backend parses this string, converts it into JPA criteria, and applies it to the query. This functionality is used extensively in the Broadleaf admin to filter list grids, but it's available in many storefront-focused APIs as well. Instead of writing dozens of hardcoded API endpoints with specific filters, you can expose one RSQL-enabled endpoint and give the caller the power to get exactly the data they need.

The Flow of a CRUD Request

A typical CRUD request in Broadleaf follows one of four primary flows, depending on whether the entity is trackable and supports RSQL.

  1. Trackable with RSQL: The most common flow, using an RSQL CRUD Entity Service and a Trackable Repository. This path leverages all of Broadleaf's core features, including data tracking and flexible filtering.
  2. Trackable without RSQL: Similar to the above, but without RSQL support.
  3. Non-Trackable (Mappable) with RSQL: Used for entities that need RSQL filtering but don't participate in data tracking.
  4. Non-Trackable (Mappable) without RSQL: The most basic flow, closest to a vanilla Spring Data repository.

In all of these flows, the fundamental pattern is the same: the REST controller delegates to a service component, which contains the business logic, and the service then delegates to a repository component for persistence or querying. The differences lie in the specific implementations that handle the extra capabilities required for the domain being acted upon.

Conclusion: The Payoff for Developers

Mastering these core domain concepts starts your project off on the right foot. For a developer, this means less time fighting boilerplate code and more time building innovative, high-impact features.

By understanding Broadleaf's architectural intent, you can:

  • Increase your development velocity: You’ll know exactly where and how to insert your custom code without breaking the platform’s core functionality.
  • Establish clear contextual boundaries for your data: Your data will be scoped to a specific tenant, application, or customer context. If your business requires another application or customer context in the future, then your data will already be safely segmented.
  • Build more resilient systems: Your extensions will be architecturally sound and less prone to issues during upgrades or when adding new features.
  • Leverage platform strengths: You can take full advantage of built-in features like data tracking and RSQL, rather than reinventing the wheel.

Ultimately, these principles empower you to solve complex commerce challenges with elegance and efficiency. For practical examples of these domain extensions, you can check out our repository on GitHub.

Related Resources