This guide targets Broadleaf Commerce Community 7.0.7-GA on Ubuntu 24.04 LTS, with PostgreSQL 17.5 as the target database and Docker 28.1.1 available if you’d rather containerise it. The reference application it ships with, Heat Clinic, is four separate Spring Boot modules stitched together by Maven, not a single container you start and forget. What follows is every version pin the build needs, the documented failure class on this stack, and the gap between “the demo runs” and “this models a real store.” Timings and command outputs below are marked for capture and have not been measured yet — every one is a placeholder rather than a guess.
Why Broadleaf Commerce Community isn’t a five-minute install
Broadleaf Commerce Community carries the Fair Use License 1.0 (opens in a new tab), not an OSI-approved open-source licence. Free use is capped at $5,000,000 USD gross revenue per trailing twelve months for an entity and its affiliates; cross that line and a paid Commercial License applies. Treat “Community” here as a pricing tier, not a guarantee of unrestricted use.
Broadleaf also sells a second, structurally different product under the same brand. The self-hosted Community/Enterprise monolith documented at monolith.broadleafcommerce.com (opens in a new tab) is what this article installs. The commercial Microservices Edition, reachable from start.broadleafcommerce.com (opens in a new tab), is a separate suite of Java/Spring services that demands an evaluation sign-up and Docker registry credentials before it generates anything — a common wrong turn if you search “Broadleaf getting started.”
The current 7.0.x line (7.0.7-GA) requires Java 17, Spring Framework 6.2 and Spring Boot 3.5.x under the Jakarta EE namespace, a hard break from the parallel 6.2.x line that still targets Java 11 and javax packages, per the project’s own 6.2-to-7.0 migration notes (opens in a new tab). The bundled Heat Clinic reference app ships as four independent Maven modules (opens in a new tab) — core, admin, api and site — each started with its own mvn spring-boot:run. This article verifies against Ubuntu 24.04 LTS, Java 17 OpenJDK, Maven 3.5.4+, PostgreSQL 17.5, Docker 28.1.1 and Broadleaf 7.0.7-GA.
flowchart TD
A[Evaluating Broadleaf Commerce] --> B{Self-host the monolith, or use the hosted product?}
B -->|Self-host: Maven, own infra, own database| C[Community/Enterprise monolith]
B -->|Hosted: many services, needs eval signup| D[Microservices Edition]
C --> E{Entity plus affiliates gross revenue, trailing 12 months}
E -->|Under 5,000,000 USD| F[Fair Use License 1.0: free]
E -->|5,000,000 USD or more| G[Paid Commercial License required]
D --> H[Requires eval signup and Docker registry credentials before anything generates]
You should now see: which product, licence and version line you’re about to install, and how to avoid landing on the commercial Microservices Edition sign-up flow by mistake.
Install Java 17, Maven and PostgreSQL 17 on Ubuntu 24.04
sudo apt install default-jdk on Ubuntu 24.04 (noble) resolves to OpenJDK 21, not the Java 17 that Broadleaf 7.0.x requires. Install the openjdk-17-jdk (opens in a new tab) package by name instead, and don’t assume the distribution default matches what the framework’s POM targets.
Ubuntu 24.04’s main repository also ships PostgreSQL 16, not 17. Getting 17.5 means adding the PGDG apt repository the PostgreSQL project maintains; the commands below fetch its signing key as a file first, so you can inspect it before trusting it.
sudo apt update
sudo apt install -y curl ca-certificates gnupg lsb-release openjdk-17-jdk maven
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc -o /tmp/postgresql-key.asc
gpg --dearmor < /tmp/postgresql-key.asc | sudo tee /usr/share/keyrings/postgresql.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
| sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install -y postgresql-17 postgresql-contrib-17If more than one JDK is present, pin the default explicitly, then confirm the toolchain versions before touching Maven.
sudo update-alternatives --config java
java -version
mvn -versionWith the packages in place, create a dedicated role and database for the Heat Clinic demo rather than reusing the postgres superuser account. Broadleaf’s own PostgreSQL configuration page (opens in a new tab) states one thing only: “Broadleaf works with a minimum PostgreSQL version of 9.2. We recommend using the latest version.” Checked 5 August 2026 — there is no upper bound and no version-by-version certification, so 17.x is neither blessed nor excluded.
sudo -u postgres psql -c "CREATE ROLE heatclinic WITH LOGIN PASSWORD 'changeme-in-production';"
sudo -u postgres psql -c "CREATE DATABASE heatclinic OWNER heatclinic;"
psql --versionRecord how long this step takes on your own host — it’s the first line item in the measured footprint carried through What the install actually costs.
You should now see: java -version reporting a 17.x OpenJDK build, mvn -version reporting 3.5.4 or later, and psql --version reporting a 17.x server, with a dedicated database ready for the demo.
Build and start the Heat Clinic demo on its default database
Clone the DemoSite repository (opens in a new tab) and check out the 7.0.7-GA tag before doing anything else, so the versions you build match the versions this article verifies against. Build against the default embedded database first — don’t touch PostgreSQL yet.
git clone https://github.com/BroadleafCommerce/DemoSite.git
cd DemoSite
git checkout tags/7.0.7-GA
mvn clean installBuilding against the default first isolates build problems from database problems. If mvn clean install fails, the cause is the JDK, Maven or a dependency resolution issue — not a Postgres misconfiguration you haven’t introduced yet. Record the wall-clock build time; it belongs in the measured footprint in section 6.
Once the build succeeds, start each of the four modules independently. Each is its own Spring Boot application with its own mvn spring-boot:run, so run them in the background and keep the logs separate.
mkdir -p logs
(cd core && mvn spring-boot:run > ../logs/core.log 2>&1 &)
(cd admin && mvn spring-boot:run > ../logs/admin.log 2>&1 &)
(cd api && mvn spring-boot:run > ../logs/api.log 2>&1 &)
(cd site && mvn spring-boot:run > ../logs/site.log 2>&1 &)If Tomcat fails to start with a NullPointerException inside Javassist’s proxy generation, that error signature matches a documented JDK-mismatch failure class recorded in DemoSite issue #57 (opens in a new tab). That report was filed against Broadleaf 6.0.6-GA on Java 11/12, so it hasn’t been confirmed to still reproduce on the current 7.0.x/Java 17 combination — but if you see it, check java -version inside the build shell before looking anywhere else.
sequenceDiagram
participant Dev as Developer shell
participant Mvn as Maven / spring-boot:run
participant Boot as Spring Boot embedded Tomcat
participant Proxy as Javassist proxy generation
Dev->>Mvn: mvn spring-boot:run, wrong JDK on PATH
Mvn->>Boot: launch embedded Tomcat
Boot->>Proxy: generate proxies for JPA entities
Proxy-->>Boot: NullPointerException in SecurityActions.setAccessible
Boot-->>Dev: Unable to start embedded Tomcat
Note over Dev,Proxy: Documented on Broadleaf 6.0.6-GA and Java 11-12, DemoSite issue 57
Note over Dev,Proxy: Not yet confirmed to reproduce on 7.0.x and Java 17
At this stage each module persists to an embedded HSQLDB flat file in the JVM’s temp directory. That’s expected, not a bug — you haven’t configured a real database yet.
You should now see: the storefront respond on :8080, the admin console on :8081/admin, and the Swagger UI on :8082/api/v1/swagger-ui.html, all backed by embedded HSQLDB, with build and startup time recorded.
Migrate the Heat Clinic demo from HSQLDB to PostgreSQL 17
A real deployment doesn’t run on an embedded flat-file database, so the next step swaps HSQLDB for the PostgreSQL role and database created in step 2. Start with the Maven dependency.
- <dependency>
- <groupId>org.hsqldb</groupId>
- <artifactId>hsqldb</artifactId>
- <scope>runtime</scope>
- </dependency>
+ <dependency>
+ <groupId>org.postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <scope>runtime</scope>
+ </dependency>Three Hibernate dialect properties need to point at Broadleaf’s Postgres dialect, and the default SQL import extractor can’t parse the multi-line demo SQL against Postgres — without a Postgres-specific extractor, the demo data import fails or throws SQL syntax errors. Broadleaf documents both changes in its PostgreSQL configuration guide (opens in a new tab).
spring.datasource.url=jdbc:postgresql://localhost:5432/heatclinic
spring.datasource.username=heatclinic
spring.datasource.password=changeme-in-production
blPU.hibernate.dialect=org.broadleafcommerce.common.extensibility.jpa.dialect.BroadleafPostgreSQLDialect
blSecurePU.hibernate.dialect=org.broadleafcommerce.common.extensibility.jpa.dialect.BroadleafPostgreSQLDialect
blCMSStorage.hibernate.dialect=org.broadleafcommerce.common.extensibility.jpa.dialect.BroadleafPostgreSQLDialect
blPU.hibernate.hbm2ddl.import_files_sql_extractor=org.broadleafcommerce.core.util.dao.DemoPostgresSingleLineSqlCommandExtractor
blPU.hibernate.hbm2ddl.auto=createSet hbm2ddl.auto=create only for the first startup against the fresh database — it drops and recreates the schema every time it runs, which is exactly what you want once and never again after.
PostgreSQL doesn’t automatically index foreign-key columns, and Broadleaf’s schema assumes those indexes exist. Run EXPLAIN against a foreign-key lookup before and after adding the missing index to see the difference directly.
EXPLAIN SELECT * FROM blc_order_item WHERE order_id = 1;CREATE INDEX idx_order_item_order_id ON blc_order_item (order_id);
EXPLAIN SELECT * FROM blc_order_item WHERE order_id = 1;Record how many attempts this migration takes — dialect mismatches and extractor errors are the most common reason it doesn’t work on the first try, and that count belongs in the measured install record alongside build and startup time.
You should now see: demo data load into PostgreSQL without SQL errors, the admin console and storefront display the same catalogue now sourced from Postgres, and the EXPLAIN plan switch from a sequential scan to an index scan after the fix.
Place a test order and check what the payment gateway actually does
Add a Heat Clinic product to the cart, complete checkout on :8080, and confirm you reach an order confirmation page. Then open the admin console at :8081/admin and confirm the same order appears in the order list — check the DemoSite repository for the current admin login rather than assuming a fixed default.
Checkout is wired to blc-sample-payment-gateway (opens in a new tab), a Broadleaf-maintained null implementation that never contacts a real payment processor. Its stated purpose is to demonstrate the shape of the gateway integration seam, not to process a payment.
There’s no charge to reconcile anywhere and no gateway credentials to configure — that’s intended behaviour, not a missing configuration step you forgot. A completed demo order proves the checkout workflow and order pipeline function end to end; it proves nothing about payment processing.
You should now see: an order confirmation page in the storefront and the same order visible in the admin console, with no payment transaction recorded anywhere in the system.
What the install actually costs: time, disk and memory, measured
Quick-start guides for most platforms publish a “minutes” framing and stop there. This section is the honest version: the method for capturing time, disk and memory at each step, so you can hold your own install against it. The numbers below are placeholders until someone runs the full sequence and records the real figures — that hasn’t happened for this article yet, and the table should be filled in from an actual run rather than trusted as printed.
time mvn clean install
du -sh /usr/lib/jvm/java-17-openjdk-amd64 ~/.m2/repository /var/lib/postgresql/17/main DemoSite/*/target
ps -o pid,%cpu,%mem,cmd -C java| Step | Wall-clock time |
|---|---|
| Install JDK, Maven, PostgreSQL | — pending measurement — |
mvn clean install | — pending measurement — |
| HSQLDB baseline startup (4 modules) | — pending measurement — |
| PostgreSQL migration and reindexing | — pending measurement — |
| First checkout to confirmation | — pending measurement — |
| Disk component | Size |
|---|---|
| JDK install | — pending measurement — |
Maven local repository (~/.m2) | — pending measurement — |
| PostgreSQL data directory | — pending measurement — |
| Four modules’ build artefacts | — pending measurement — |
| Resource | Peak, all 4 modules running |
|---|---|
| RAM | — pending measurement — |
| CPU | — pending measurement — |
Filling in that first table honestly usually takes longer than the “five-minute” framing common in other platforms’ quick starts, because Broadleaf’s real footprint is four separate JVMs and a relational database, not one process behind a single command.
You should now see: a table you can hold your own install against — total time, disk used, and peak memory and CPU with all four modules running — once you’ve captured the real numbers on your host.
The functional gap between ‘installed’ and ‘evaluation-ready’
Broadleaf’s own documentation states that embedded Solr — the demo’s default search engine — is fine for getting started but explicitly unfit for large catalogues, high traffic, or any multi-node cluster (opens in a new tab), since each node reindexes independently. That’s a vendor-stated limit, not a criticism.
The reference app proves the storefront, admin console and checkout pipeline run together. It doesn’t prove search at production scale, real payment processing, or multi-node deployment — the null gateway from section 5 and the embedded-Solr caveat here are the same category of gap: a working demo path standing in for infrastructure a real store still needs.
flowchart LR
subgraph Proven["What the Heat Clinic install proves"]
A[Storefront renders on :8080]
B[Admin console manages catalogue on :8081]
C[Checkout pipeline completes an order]
D[REST API responds on :8082]
end
subgraph NotProven["What it does not prove"]
E[Search at catalogue and traffic scale]
F[Real payment processing]
G[Multi-node deployment]
H[A modern JS storefront]
end
Proven -.budget separately.-> NotProven
Broadleaf also ships no modern JavaScript storefront of its own. Heat Clinic’s server-rendered reference site demonstrates the storefront APIs; it isn’t a template for a headless frontend, and treating it as one means rebuilding the rendering layer from scratch anyway.
“Installed” and “ready to model a production storefront” are different claims, and the difference is search infrastructure, payment integration and frontend work — not configuration you toggle on.
You should now see: which parts of a production storefront the Heat Clinic install has and hasn’t validated, before you scope a proof of concept around it.
Pair Broadleaf’s REST API with svelte-commerce, a disclosed experiment
Broadleaf ships no headless-ready storefront of its own, so this section wires its REST API to svelte-commerce (opens in a new tab), a SvelteKit storefront maintained by this article’s author. Disclosure first: svelte-commerce’s built-in connectors target Litekart and Medusa.js; WooCommerce, BigCommerce, Shopify and Magento are marked work in progress. There is no existing Broadleaf connector — what follows is custom integration code written for this article, not a documented or supported pairing.
PUBLIC_API_BASE_URL=http://localhost:8082/api/v1
PUBLIC_STOREFRONT_MODE=broadleaf-customexport async function fetchBroadleafProducts(category?: string) {
const url = new URL(`${import.meta.env.PUBLIC_API_BASE_URL}/catalog/products`);
if (category) url.searchParams.set('category', category);
const res = await fetch(url.toString(), {
headers: { Accept: 'application/json' },
});
if (!res.ok) throw new Error(`Broadleaf API returned ${res.status}`);
const data = await res.json();
return data.products.map((p: any) => ({
id: p.id,
slug: p.url,
title: p.name,
price: p.price?.amount,
currency: p.price?.currency,
image: p.primaryImage?.url,
}));
}sequenceDiagram
participant SC as svelte-commerce (SvelteKit)
participant API as Broadleaf api module :8082
SC->>API: GET product listing, custom fetch client
API-->>SC: JSON product data, this pass's scope
SC->>API: GET product detail
API-->>SC: JSON product data, this pass's scope
SC-->>API: Full checkout flow, out of scope this pass
SC-->>API: Authentication, out of scope this pass
This pass targets product listing and detail against the Swagger-documented endpoints on :8082/api/v1/swagger-ui.html. Full checkout and authentication are out of scope for this integration — the fetch client above doesn’t attempt either, so don’t read this section as evidence that a complete headless checkout exists.
If you’re scoping a proof of concept from here, budget separately for search infrastructure beyond embedded Solr, a real payment gateway integration to replace the sample, and the frontend work this pairing only starts — none of it is exercised by the install in this article.
You should now see: the scope and limits of this pairing stated explicitly — what a custom Broadleaf-to-svelte-commerce client covers, and what it deliberately leaves for later work.
Limitations
This article covers a single-host development install, not a production deployment — it doesn’t touch TLS, secrets management, backups, or horizontal scaling of any of the four modules. PostgreSQL compatibility is stated by Broadleaf as a 9.2 minimum with a recommendation to use the latest release, and nothing more granular; no vendor document certifies the 17.x line specifically. The Javassist NullPointerException in section 3 is a historical failure class documented against Broadleaf 6.0.6-GA on Java 11/12, not a failure reproduced on 7.0.7-GA and Java 17 for this article. Timing, disk and memory figures in section 6 are placeholders pending an actual measured run, not published numbers. The svelte-commerce pairing in section 8 covers product listing and detail only — checkout, authentication, multi-node deployment, and search beyond embedded Solr are unexercised by anything in this guide.