Introduction | Core Concept | Mechanics | Components | Getting Started | Build Nano | Benefits
Back to basics and forget about frameworks!
Nano is a lightweight approach which makes it easier for developer to write microservices in functional, fluent, chaining, plain, modern java with a nano footprint. It breaks away from traditional OOP patterns. Instead of creating complex object hierarchies with Controllers, Services, and Repositories, Nano uses static event listeners that react to events in a functional, stateless manner.
Key Philosophy:
- Static Methods, Not Objects: Business logic lives in static methods, not in service objects
- Event-Driven Communication: Everything communicates through events, not direct method calls
- Universal Services: Services are generic connectors for external systems (databases, HTTP, queues) - no business logic
- TypeMap Everywhere: Built-in type conversion and data transformation using TypeMap
- Global Error Handling: Even errors are events that can be subscribed to and handled globally
Nano is designed to be fully compilable with GraalVM to create native executables and utilizes non-blocking virtual threads from Project Loom for maximum performance.
Think Events, Not Objects!
Nano revolutionizes microservice development by eliminating the need for complex object hierarchies. Instead of creating Controllers, Services, and Repositories, you simply listen to events and react with static methods.
How It Works:
- Events Flow Through Everything: HTTP requests, database operations, errors - all are events
- Static Listeners React: Your business logic lives in static methods that subscribe to events
- Services Are Universal Connectors: Services handle external integrations (HTTP, databases, queues) - no business logic
- TypeMap Handles Data: Automatic type conversion for JSON, XML, and any data format
- Global Error Handling: Subscribe to error events for centralized error management
Example - Traditional vs Nano:
// ❌ Traditional Spring Boot
@RestController
public class UserController {
@Autowired private UserService userService;
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody UserDto dto) {
return ResponseEntity.ok(userService.createUser(dto));
}
}
// ✅ Nano - Static Event Handling
public class UserController {
public static void handleCreateUser(Event<HttpObject, HttpObject> event) {
event.payloadOpt()
.filter(HttpObject::isMethodPost)
.filter(req -> req.pathMatch("/users"))
.ifPresent(req -> {
// Business logic here - no objects needed!
event.context().sendEvent(EVENT_CREATE_USER, req.bodyAsJson().asMap());
req.createResponse().statusCode(200).respond(event);
});
}
}All you need to know are few classes: Context, Events, Schedulers, Services
flowchart LR
nano(((Nano))) --> context[Context]
context --> ch[Channels]
nano --> services[Services]
context --> schedulers[Schedulers]
ch -->|sendEvent| listeners[Listeners]
services -->|ack/reply| responses[(Responses)]
listeners -->|ack/reply| responses[(Responses)]
style nano fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
style context fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
style ch fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
style listeners fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
style responses fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
style services fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
style schedulers fill:#90CAF9,stroke:#1565C0,stroke-width:1px,color:#1A237E,rx:2%,ry:2%
The Nano Way: Static, Event-Driven, and Stateless
Nano's architecture is fundamentally different from traditional frameworks:
🏗️ Architecture Principles:
- Static Methods for Business Logic: No need for service objects - just static methods that react to events
- Services as Universal Connectors: Services handle external integrations only (databases, HTTP, queues) - no business logic
- Event-Driven Communication: Everything flows through events - HTTP requests, database operations, errors
- TypeMap for Data Handling: Automatic type conversion and transformation for JSON, XML, and any data format
- Global Error Handling: Subscribe to error events for centralized error management
- Built-in Logging: Context automatically provides logging - no setup required
🔄 How It All Connects:
- HTTP Request → Event → Static Listener → Business Logic
- Database Operation → Event → Database Service → Response Event
- Error Occurs → Error Event → Global Error Handler → Error Response
- Error Handling
- Registers (ConfigRegister, TypeConversionRegister, LogFormatRegister, EventChannelRegister)
- Integrations (🌱 Spring Boot, 🧑🚀 Micronaut, 🐸 Quarkus)
- Code Examples
Maven example
<dependency>
<groupId>org.nanonative</groupId>
<artifactId>nano</artifactId>
<version>2025.1.0</version>
</dependency>Gradle example
dependencies {
implementation 'org.nanonative:nano:2025.1.0'
}New to Nano? Start with our Quick Start Guide for a complete walkthrough.
Want to see examples? Check out our Examples & Common Solutions with real-world patterns.
Building a web API? Check out our HTTP Service Guide with real-world examples.
Need architecture guidance? See our Core Concepts for best practices.
Looking for documentation? Check out our comprehensive guides in the docs directory.
Here's a basic HTTP server with Nano showing the event-driven approach:
public static void main(final String[] args) {
// Start Nano with HttpServer
final Nano app = new Nano(args, new HttpServer());
// Static method handles GET /hello - no @Controller needed!
app.subscribeEvent(EVENT_HTTP_REQUEST, MyController::handleHello);
// Global error handling - even errors are events!
app.subscribeError(EVENT_HTTP_REQUEST, MyController::handleError);
}
public class MyController {
// Static method for business logic - no objects, no state!
public static void handleHello(Event<HttpObject, HttpObject> event) {
event.payloadOpt()
.filter(HttpObject::isMethodGet)
.filter(request -> request.pathMatch("/hello"))
.ifPresent(request -> request.createResponse()
.body(Map.of("Hello", System.getProperty("user.name")))
.respond(event));
}
// Global error handling - subscribe to error events!
public static void handleError(Event<?, ?> event) {
event.payloadAck()
.createResponse()
.body("Internal Server Error [" + event.error().getMessage() + "]")
.statusCode(500)
.respond(event);
}
}- Complete Examples: See our Examples & Common Solutions for comprehensive patterns
- User Management: Check out our Simple User API Example
- More Examples: Browse all examples in src/test/java/org/nanonative/nano/examples/
add the native-image profile to your pom.xml and run mvn package -Pnative-image
<profiles>
<!-- NATIVE COMPILATION -->
<plugin>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>native-image-maven-plugin</artifactId>
<version>21.2.0</version>
<configuration>
<imageName>ExampleApp</imageName>
<mainClass>de.yuna.berlin.nativeapp.helper.ExampleApp</mainClass>
<buildArgs>
<!-- Reduces the image size - Ensures the native image doesn't include the JVM as a fallback option -->
<buildArg>--no-fallback</buildArg>
<!-- Disables the use of the GraalVM compilation server -->
<buildArg>--no-server</buildArg>
<!-- Improve startup time - Initialize classes at build time rather than at runtime -->
<buildArg>--initialize-at-build-time</buildArg>
<!-- Include all files under /resources -->
<buildArg>-H:IncludeResources=resources/config/.*</buildArg>
</buildArgs>
</configuration>
<executions>
<execution>
<goals>
<goal>native-image</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</profiles>🎯 Revolutionary Approach:
- 🚫 No More Object Hierarchies: Forget Controllers, Services, Repositories - just static methods and events!
- 📡 Event-Driven Everything: HTTP requests, database operations, errors - all flow through events
- 🔧 Universal Services: Services are generic connectors for external systems - no business logic mixed in
- 🗺️ TypeMap Magic: Automatic type conversion for JSON, XML, and any data format - no manual mapping needed
- 🛡️ Global Error Handling: Subscribe to error events for centralized error management
- 📝 Built-in Logging: Context automatically provides logging - no setup, no configuration needed
⚡ Performance & Simplicity:
- 🪶 Lightweight & Fast: Starts in milliseconds, uses ~10MB memory
- 🌿 Pure Java, Pure Simplicity: No reflections, no regex, no unnecessary magic
- ⚡ GraalVM Ready: For ahead-of-time compilation and faster startup
- 🔒 Minimal Dependencies: Reduces CVE risks and simplifies updates
- 🧵 Virtual Threads: Built-in support for Project Loom's virtual threads
- 🚀 Scalable and Performant: Designed for high-concurrency scenarios
🛠️ Developer Experience:
- 🌊 Fluent & Stateless: Intuitive API design for easy readability and maintenance
- 🧩 Modular Design: Easy to understand, extend, and maintain
- ⚙️ Flexible Configuration: Environment variables, system properties, command-line arguments
- 🧪 Test-Friendly: Easy to test with fake services and event listeners
- 🛠️ Rapid Development: Build real services in minutes, not hours
Contributions to Nano are welcome! Please refer to our Contribution Guidelines for more information.
Nano is open-source software licensed under the Apache license.
If you encounter any issues or have questions, please file an issue here.
