Getting Started with BLOGE
This guide walks from a single node to a small production-style setup. Every section shows both the Java builder style and the equivalent .bloge DSL so teams can choose the authoring style that fits their workflow.
Prerequisites
- Java 25+
- Maven 3.6+
- Node.js 18+ only if you want to run Bloge Studio locally
Add the BLOGE dependencies you need to your pom.xml. At minimum, bloge-core is always required. See Appendix: Maven dependencies for the full coordinates of all modules.
Available modules
| Module | Description | When to add |
|---|---|---|
bloge-core | Core engine with zero external dependencies (java.base only) | Always |
bloge-core-ext | Session/phase/round extension runtime and compilers | Session, phase, or round flows |
bloge-dsl | External DSL parser and compiler for .bloge files | When loading .bloge files |
bloge-durable | Durable execution support: InMemory and JDBC checkpoint stores | Long-running or resumable flows |
bloge-durable-codec | Checkpoint codec implementations for durable module | Together with bloge-durable |
bloge-spring | Spring Boot auto-configuration for BLOGE | Spring Boot apps |
bloge-metrics-otel | Micrometer metrics, Micrometer Tracing spans, OpenTelemetry context propagation, SLF4J MDC propagation | Observability |
bloge-common-operators | Production-grade common operator library — HTTP, DB, Messaging, AI/LLM, Transform, Notification, Approval, Storage, Crypto, Validation | Pre-built operator library |
bloge-lint | Lint tool and CLI for .bloge DSL files | DSL authoring or CI lint |
bloge-test | Test tools: MockOperator, GraphTestRunner, DslTestHelper | Testing |
bloge-bpmn-transformer | BPMN 2.0 XML to BLOGE DSL and Graph translator for legacy system migration | BPMN migration |
bloge-script | Optional sandboxed Groovy script execution for bloge script nodes | Script nodes |
1. Single-node echo graph
The smallest useful graph is one node that reads context and returns a value.
Java API
Graph graph = Graph.builder("echo")
.node("echo", (Map<String, Object> input, OperatorContext ctx) ->
Map.of("message", ctx.graphContext().get("message", String.class)))
.build();
GraphResult result = GraphEngine.builder().build()
.execute(graph, new GraphContext(Map.of("message", "hello")));DSL
graph echo {
node echo : EchoOperator {
input {
message = ctx.message
}
}
}DefaultOperatorRegistry registry = new DefaultOperatorRegistry();
registry.register("EchoOperator", (input, ctx) -> input);
Graph graph = new GraphLoader(registry).load(dslSource);
GraphResult result = GraphEngine.builder().registry(registry).build()
.execute(graph, new GraphContext(Map.of("message", "hello")));What to notice:
- Java is ideal when operators and schemas already live in code.
- DSL is ideal when you want a reviewable artifact that can be edited without recompiling Java classes.
2. Two-node sequential graph
Now add a downstream node that depends on the first node's output.
Java API
Graph graph = Graph.builder("greetUser")
.node("fetchUser", fetchUserOperator)
.node("formatGreeting", formatGreetingOperator)
.dependsOn("fetchUser")
.build();DSL
graph greetUser {
node fetchUser : FetchUserOperator {
input {
userId = ctx.userId
}
}
node formatGreeting : FormatGreetingOperator {
input {
user = fetchUser.output
}
}
}The DSL compiler infers the dependency from fetchUser.output, so you do not have to repeat depends_on unless you want to make the edge explicit.
3. Parallel fan-out plus branch
BLOGE becomes interesting when multiple upstream calls can run concurrently and a later step decides which path to take.
Java API
Graph graph = Graph.builder("orderDecision")
.node("fetchUser", fetchUserOperator)
.node("fetchProducts", fetchProductsOperator)
.node("calcPrice", calcPriceOperator)
.dependsOn("fetchUser", "fetchProducts")
.branch("calcPrice")
.on("approved")
.when(value -> Boolean.TRUE.equals(value), "createOrder")
.otherwise("rejectOrder")
.node("createOrder", createOrderOperator)
.node("rejectOrder", rejectOrderOperator)
.build();DSL
graph orderDecision {
node fetchUser : FetchUserOperator {
input {
userId = ctx.userId
}
}
node fetchProducts : FetchProductsOperator {
input {
productIds = ctx.productIds
}
}
node calcPrice : CalcPriceOperator {
input {
user = fetchUser.output
products = fetchProducts.output
}
}
branch on calcPrice.output.approved {
true -> createOrder
otherwise -> rejectOrder
}
node createOrder : CreateOrderOperator {}
node rejectOrder : RejectOrderOperator {}
}What to notice:
fetchUserandfetchProductscan run in parallel because nothing depends on the other.- the branch is control flow, not data transformation; use
transformwhen you only want to compute a value.
4. Java and DSL are equivalent authoring styles
The same business graph can be expressed in either form. A practical workflow is:
- prototype the graph in DSL
- prove behavior with tests or golden baselines
- move stable operator logic into Java classes
- keep the graph shape in DSL or generate it from Studio
Java API
Graph graph = Graph.builder("ticketRouting")
.node("fetchCustomer", fetchCustomerOperator)
.node("analyzeSentiment", sentimentOperator)
.dependsOn("fetchCustomer")
.branch("analyzeSentiment")
.on("priority")
.when(value -> "vip".equals(value), "assignVipAgent")
.when(value -> "normal".equals(value), "assignNormalAgent")
.otherwise("autoResolve")
.node("assignVipAgent", assignVipAgentOperator)
.node("assignNormalAgent", assignNormalAgentOperator)
.node("autoResolve", autoResolveOperator)
.build();DSL
graph ticketRouting {
node fetchCustomer : FetchCustomerOperator {
input {
ticketId = ctx.ticketId
}
}
node analyzeSentiment : AnalyzeSentimentOperator {
input {
customer = fetchCustomer.output
}
}
branch on analyzeSentiment.output.priority {
"vip" -> assignVipAgent
"normal" -> assignNormalAgent
otherwise -> autoResolve
}
node assignVipAgent : AssignVipAgentOperator {}
node assignNormalAgent : AssignNormalAgentOperator {}
node autoResolve : AutoResolveOperator {}
}Use the Java style when type-safe composition inside the same codebase is more important than external authoring. Use DSL when product, operations, or tooling teams need a standalone graph artifact.
5. Spring Boot integration
bloge-spring lets a normal Spring Boot app publish operators and load .bloge files automatically.
Java API inside Spring Boot
@Configuration
class BlogeGraphs {
@Bean
Graph orderGraph() {
return Graph.builder("orderGraph")
.node("fetchUser", new FetchUserOperator())
.build();
}
}DSL inside Spring Boot
Add the dependency:
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-spring</artifactId>
<version>0.3.1</version>
</dependency>Create an operator bean:
@BlogeOperator("FetchUserOperator")
@Component
class FetchUserOperator implements Operator<Map<String, Object>, Map<String, Object>> {
@Override
public Map<String, Object> execute(Map<String, Object> input, OperatorContext ctx) {
return Map.of("id", input.get("userId"));
}
}Create src/main/resources/bloge/order-graph.bloge:
graph orderGraph {
node fetchUser : FetchUserOperator {
input {
userId = ctx.userId
}
}
}At runtime, inject GraphEngine and the discovered graphs, then execute the graph that matches your route or use case.
6. Studio visualization
bloge-studio is the visual editor for teams who want to model a graph before checking in the DSL.
Studio workflow
- start the UI locally:
cd bloge-studio
npm install
npm run dev- create nodes and edges visually
- export the generated
.blogesource - commit the DSL file into
src/main/resources/bloge/ - execute it with the same
GraphLoaderflow shown earlier
DSL output from Studio
graph studioDraft {
node fetchProfile : FetchProfileOperator {
input {
userId = ctx.userId
}
}
node enrichProfile : EnrichProfileOperator {
input {
profile = fetchProfile.output
}
}
}Equivalent Java API
Graph graph = Graph.builder("studioDraft")
.node("fetchProfile", fetchProfileOperator)
.node("enrichProfile", enrichProfileOperator)
.dependsOn("fetchProfile")
.build();Studio is best treated as an authoring surface, not a separate runtime. The execution path remains the same Java engine that runs every other BLOGE graph.
Next steps
- Prefer a chapter-by-chapter path? Follow Head First BLOGE for the full tutorial track in English and Chinese.
- Browse Example Catalog for larger runnable graphs.
- Read Full Specification for the full language contract.
- If you need long-running conversational flows, continue with the session / phase / round extension docs in the repository and the DSL reference in this site.
- If you need production persistence or observability, continue with Durable Flows and Observability.
Appendix: Maven dependencies
All BLOGE modules share the same groupId and version. Copy the coordinates for the modules your project requires.
<!-- Core engine — always required -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-core</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Session/phase/round extension runtime and compilers -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-core-ext</artifactId>
<version>0.3.1</version>
</dependency>
<!-- External DSL parser and compiler for .bloge files -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-dsl</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Durable execution support: InMemory and JDBC checkpoint stores -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-durable</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Checkpoint codec implementations for durable module -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-durable-codec</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Spring Boot auto-configuration for BLOGE -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-spring</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Observability: Micrometer metrics, Micrometer Tracing spans, OpenTelemetry, SLF4J MDC -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-metrics-otel</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Production-grade common operator library: HTTP, DB, Messaging, AI/LLM, Transform, etc. -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-common-operators</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Lint tool and CLI for .bloge DSL files -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-lint</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Test tools: MockOperator, GraphTestRunner, DslTestHelper -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-test</artifactId>
<version>0.3.1</version>
</dependency>
<!-- BPMN 2.0 XML to BLOGE DSL and Graph translator -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-bpmn-transformer</artifactId>
<version>0.3.1</version>
</dependency>
<!-- Optional sandboxed Groovy script execution for bloge script nodes -->
<dependency>
<groupId>com.leanowtech.bloge</groupId>
<artifactId>bloge-script</artifactId>
<version>0.3.1</version>
</dependency>