The Reality Check
You know that feeling when you inherit a 35,000-line Spring Boot monster that does basic CRUD? Or when you realize your “modern” web stack needs 47 dependencies to display a table? Codion exists because we’ve all been there.
This isn’t another framework promising to “revolutionize development.” This is battle-tested code that’s kept critical infrastructure running for decades—from marine research vessels to national fishing quota systems. While others chase the latest JavaScript trend, Codion has been quietly solving real problems.
🧬 Observable Architecture: Everything Reacts
Forget manual event handling. In Codion, your UI automatically stays in sync because everything is observable.
// State that automatically controls UI elements
State processing = State.state();
State hasData = State.state();
State canSubmit = State.and(hasData, processing.not());
// Values that propagate changes throughout your app
Value<String> searchFilter = Value.builder()
.nullable()
.listener(this::updateResults)
.build();
// UI components that bind to state - no manual wiring
JButton submitButton = button(submitAction)
.enabled(canSubmit)
.build();
Your code describes what should happen, not how to keep everything synchronized. Change a value anywhere, and every dependent UI element updates automatically. No Redux. No useState hooks. No callback hell.
🏗️ Domain-First Design: Your Business Logic Runs Everything
Define your domain once. Get CRUD operations, UI forms, validation, and queries for free.
// This isn't just a schema - it's executable business logic
interface Customer {
EntityType TYPE = DOMAIN.entityType("store.customer");
Column<String> EMAIL = TYPE.stringColumn("email");
Column<String> PHONE = TYPE.stringColumn("phone");
Column<BigDecimal> CREDIT_LIMIT = TYPE.bigDecimalColumn("credit_limit");
Column<Integer> ADDRESS_ID = TYPE.integerColumn("address_id");
// Foreign keys are first-class citizens, not afterthoughts
ForeignKey ADDRESS_FK = TYPE.foreignKey("address_fk", ADDRESS_ID, Address.ID);
}
// Configure behavior once, use everywhere
Customer.EMAIL.define()
.column()
.caption("Email")
.nullable(false)
.searchable(true)
.maximumLength(255);
Customer.ADDRESS_FK.define()
.foreignKey()
.caption("Address");
This definition automatically generates type-safe CRUD operations, form validation and UI components, search and filter capabilities, foreign key navigation and loading, and database query optimizations.
No separate DTOs. No mapping layers. No synchronization headaches.
🚀 Performance That Actually Scales
While your React app chokes on 1000 rows, Codion applications are built for serious performance. Load testing proves 8000+ concurrent users capability, though real-world usage in Iceland typically involves dozens of concurrent users (it’s a small country, after all).
Real metrics from production systems: Marine research vessel with 24/7 uptime collecting biological measurements. National catch registration system handling entire country’s fishing industry. Scientific databases serving researchers for over two decades.
// Built-in load testing because performance matters
LoadTest.builder(applicationFactory, Application::close)
.user(TEST_USER)
.scenarios(List.of(
scenario(new InsertCustomer(), 1), // Weight: 1
scenario(new SearchCustomers(), 10), // Weight: 10
scenario(new GenerateReport(), 2))) // Weight: 2
.build();
Why it’s fast: The database layer essentially boils down to HashMap lookups and string concatenation. Domain metadata enables intelligent query optimization where the framework knows exactly which columns to fetch, how to join tables efficiently, and when to cache results - all without runtime reflection or complex object mapping.
🎯 Desktop UI That Doesn’t Suck
Rich components. Keyboard navigation. Real accessibility. Everything your users actually want.
// Tables that handle thousands of rows without breaking a sweat
FilterTable<Customer, CustomerColumn> table = FilterTable.builder(model, columns)
.sortable(true)
.autoResizeMode(AUTO_RESIZE_ALL_COLUMNS)
.doubleClick(command(this::editCustomer))
.keyEvent(KeyEvents.builder(VK_DELETE)
.condition(WHEN_FOCUSED)
.action(command(this::deleteSelected)))
.build();
// Forms that validate in real-time
JTextField emailField = stringField(customer.email())
.validator(EmailValidator.INSTANCE)
.transferFocusOnEnter(true)
.selectAllOnFocusGained(true)
.build();
Keyboard-first design with Enter
transferring focus by default and plenty of shortcuts for power users. Master-detail relationships with fractal UI that scales to any complexity. Real-time validation that catches errors before users hit save. Network resilience with graceful handling of connection issues.
🔗 Foreign Keys as First-Class Citizens
Stop writing join queries. Stop managing object relationships. Let Codion handle it.
// Define relationships once
interface Order {
ForeignKey CUSTOMER_FK = TYPE.foreignKey("customer_fk", CUSTOMER_ID, Customer.ID);
ForeignKey SHIPPING_ADDRESS_FK = TYPE.foreignKey("shipping_fk", SHIPPING_ID, Address.ID);
}
// Use them everywhere
Entity order = connection.selectSingle(Order.ID.equalTo(42));
Entity customer = order.get(Order.CUSTOMER_FK); // Already loaded
String customerName = customer.get(Customer.NAME); // No extra queries
String customerEmail = customer.get(Customer.EMAIL); // Still no extra queries
// Control loading depth for performance
Order.CUSTOMER_FK.define()
.foreignKey()
.attributes(Customer.NAME, Customer.EMAIL) // Only fetch what you need
.referenceDepth(2); // Customer -> Address -> Country
Your code reads like business logic, not database plumbing.
💾 Database Agnostic (Actually)
Support for databases you’ve heard of, with battle-tested implementations.
Production-proven:
- PostgreSQL ⭐ (Default choice for new projects)
- Oracle ⭐ (Enterprise environments)
- H2 ⭐ (Development and testing)
Production-ready:
- SQL Server, MariaDB, MySQL, Derby, HSQL, SQLite, DB2
// Same code, any database
EntityConnection connection = connectionProvider.connection();
// Type-safe queries that work everywhere
List<Entity> activeCustomers =
connection.select(
and(Customer.ACTIVE.equalTo(true),
Customer.REGISTRATION_DATE.greaterThan(lastMonth)));
// Transactions that actually work
EntityConnection.transaction(connection, () -> {
Entity customer = connection.insert(newCustomer);
Entity order = connection.entities().builder(Order.TYPE)
.with(Order.CUSTOMER_FK, customer)
.build();
connection.insert(order);
connection.insert(orderLines);
// Automatic rollback on any exception
});
🧪 Testing That Doesn’t Hate You
Clear separation between business logic and UI. Real tests from real applications.
// Test domain model structure (from Petstore demo)
public class PetstoreTest extends DomainTest {
public PetstoreTest() {
super(new Petstore());
}
@Test
void address() {
test(Address.TYPE); // Tests CRUD operations, constraints, foreign keys
}
@Test
void product() {
test(Product.TYPE); // Validates entity definition and relationships
}
@Test
void item() {
test(Item.TYPE); // Verifies domain integrity automatically
}
}
// Test domain validation (from Petclinic demo)
@Test
void validation() {
try (EntityConnectionProvider connectionProvider = createConnectionProvider()) {
EntityConnection connection = connectionProvider.connection();
VetSpecialtyEditModel model = new VetSpecialtyEditModel(connectionProvider);
Entity linda = connection.selectSingle(Vet.FIRST_NAME.equalTo("Linda"));
Entity surgery = connection.selectSingle(Specialty.NAME.equalTo("surgery"));
model.editor().value(VetSpecialty.VET_FK).set(linda);
model.editor().value(VetSpecialty.SPECIALTY_FK).set(surgery);
// Business rule: Linda already specializes in surgery
assertThrows(ValidationException.class, model::insert);
}
}
// Test table model behavior (from Chinook demo)
@Test
void raisePriceOfSelected() {
try (EntityConnectionProvider connectionProvider = createConnectionProvider()) {
Entity masterOfPuppets = connectionProvider.connection()
.selectSingle(Album.TITLE.equalTo("Master Of Puppets"));
TrackTableModel trackTableModel = new TrackTableModel(connectionProvider);
trackTableModel.queryModel().condition()
.get(Track.ALBUM_FK).set().equalTo(masterOfPuppets);
trackTableModel.items().refresh();
assertEquals(8, trackTableModel.items().visible().count());
trackTableModel.selection().selectAll();
trackTableModel.raisePriceOfSelected(BigDecimal.ONE);
// Verify all tracks now cost $1.99
trackTableModel.items().get().forEach(track ->
assertEquals(BigDecimal.valueOf(1.99), track.get(Track.UNITPRICE)));
}
}
Testing philosophy:
- Domain logic is pure and testable
- Built-in domain test base class verifies entity integrity
- Model behavior verified through real scenarios
- H2 in-memory database for fast test cycles
🎨 Modern Look & Feel
Beautiful, modern themes that users actually want to look at. No more gray boxes from 1995.
// Include FlatLaF plugin for modern flat themes
<dependency>
<groupId>is.codion</groupId>
<artifactId>codion-plugin-flatlaf</artifactId>
<version>0.18.38</version>
</dependency>
// Add 40+ IntelliJ-based themes
<dependency>
<groupId>is.codion</groupId>
<artifactId>codion-plugin-flatlaf-intellij-themes</artifactId>
<version>0.18.38</version>
</dependency>
What you get:
- 40+ professional themes from IntelliJ theme collections
- Dynamic theme switching - change themes without restarting the application
- Built-in theme selector component for user preferences
- Flat design with proper typography and spacing
- Dark mode support with multiple dark theme variants
Popular theme collections:
- Material themes - Material Darker, Oceanic, NightOwl
- Nature themes - Aurora Borealis, Autumn, Everest, Sakura
- Developer favorites - Dracula, One Dark, Gruvbox, Nord
- Modern variants - GitHub Dark/Light, Arc, Cyberpunk
Built-in theme management: Every Codion application automatically includes a View → Select look and feel menu item that opens a theme selector. The combo box shows each theme name with a visual preview of its key colors, making it easy for users to see what each theme looks like before applying it.
// Users can change themes instantly via UI
LookAndFeelSelectionDialogBuilder.lookAndFeelSelectionDialog()
.owner(parentFrame)
.show();
The experience: Select a new theme from the dropdown and watch your entire application instantly transform - menus, buttons, tables, forms, everything updates immediately. No restart required, no flickering, just smooth transitions to your preferred aesthetic.
Why this matters: Your desktop applications look professional and modern. Users can customize their experience with themes they love. No more apologizing for “legacy desktop UI” - these applications look better than most web apps.
🤖 5GL Ready: Built for AI
Codion’s API design makes it perfect for AI-assisted development. Every method takes parameters, every pattern is consistent, every abstraction is discoverable.
// This API is LLM-friendly because it's parameter-based
StringField.builder()
.value(customer.email())
.nullable(false) // Instead of nullable()
.transferFocusOnEnter(true) // Instead of transferFocusOnEnter()
.selectAllOnFocusGained(true) // Instead of selectAllOnFocusGained()
.validator(EmailValidator.INSTANCE)
.build();
// AI can mechanically generate this from UI mockups or requirements
FilterTable.builder(model, columns)
.sortable(true)
.selectionMode(SINGLE_SELECTION)
.autoResizeMode(AUTO_RESIZE_ALL_COLUMNS)
.build();
What this enables:
- LLMs can generate working Codion code from descriptions
- Mechanical transformation of existing applications
- Automated migration from other frameworks
- Tool-generated UIs that actually compile and run
📦 Deployment: From Local to Enterprise
Local development: Embedded H2 database, single JAR deployment
Team development: PostgreSQL server, RMI connections
Enterprise deployment: Oracle backend, thousands of concurrent users
// Same application code, different connection strategies
Database database = new H2DatabaseFactory()
.create("jdbc:h2:mem:h2db;DB_CLOSE_DELAY=-1");
EntityConnectionProvider localProvider =
LocalEntityConnectionProvider.builder()
.domain(new StoreDomain())
.database(database)
.build();
EntityConnectionProvider remoteProvider =
RemoteEntityConnectionProvider.builder()
.domainType(Store.DOMAIN)
.hostName("production-server")
.port(1142)
.build();
Deployment options:
- Local JDBC - Single user, embedded database
- RMI Server - Multiple users, shared database
- HTTP Server - Web-accessible endpoints
- Hybrid - Mix connection types as needed
⚡ Migration Stories: From Mess to Maintainable
Real migration: 35,000 lines of spaghetti code → 21,000 lines of clean Codion. 4 months. Still running over a decade later.
// Before: Spring Boot controller hell
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
@Autowired CustomerService customerService;
@Autowired AddressService addressService;
@Autowired OrderService orderService;
@GetMapping("/{id}")
public ResponseEntity<CustomerDTO> getCustomer(@PathVariable Long id) {
Customer customer = customerService.findById(id)
.orElseThrow(() -> new CustomerNotFoundException(id));
Address address = addressService.findByCustomerId(id);
List<Order> orders = orderService.findByCustomerId(id);
CustomerDTO dto = new CustomerDTO();
dto.setId(customer.getId());
dto.setName(customer.getName());
dto.setEmail(customer.getEmail());
// ... 50 more lines of mapping
return ResponseEntity.ok(dto);
}
}
// After: Codion just works
Entity customer = connection.selectSingle(Customer.ID.equalTo(customerId));
String name = customer.get(Customer.NAME);
String email = customer.get(Customer.EMAIL);
Entity address = customer.get(Customer.ADDRESS_FK); // Automatic loading
Migration path:
- Define domain entities from existing schema
- Replace repositories with EntityConnection
- Migrate forms to EntityEditPanel
- Replace tables with EntityTablePanel
- Delete boilerplate (lots of it)
📊 Complexity Trends: Descending from Peak
A decade of refinement shows in the metrics:
- Lines of code growing
- Cognitive complexity flat
- Cyclomatic complexity not scaling with codebase size
- Result: More features, same mental overhead
Recent improvements:
- 360+ API renames for clarity
- 237+ deprecated method removals
- Consistent builder patterns throughout
- Practically zero breaking changes for end users
🛠️ Developer Experience
IDE Integration
- Full IntelliJ support with live templates
- Refactoring-friendly APIs throughout
- Type-safe navigation to domain definitions
- Debugger integration for reactive state
Code Generation
- Domain generators from database schemas
- Report integration with JasperReports
- Custom generators via extensible framework
Documentation
- Live examples in the codebase
- Comprehensive manual with working code
- Demo applications showing real patterns
🎭 The Three Personalities
Codion adapts to your needs:
1. Pure UI Framework (SDKBOY demo)
Just the codion-swing-common-ui
module and deps. No CRUD. Perfect for tools and utilities.
2. Hybrid Approach (Llemmy demo)
Minimal entities for persistence, custom UI for everything else. Best of both worlds.
3. Full Framework (Chinook demo)
Complete domain-driven CRUD with generated UIs. Maximum productivity for business applications.
🎯 Who Should Use Codion
Perfect for:
- Internal business applications
- Data-heavy applications with complex relationships
- Teams tired of web framework churn
- Projects that need to last decades
- Developers who value keyboard navigation and desktop UX
- Organizations with existing database schemas
Not ideal for:
- Public-facing web applications
- Mobile-first experiences
- Real-time gaming or multimedia
- Teams committed to browser-only deployment
🚦 Getting Started
# Add to your Maven project
<dependency>
<groupId>is.codion</groupId>
<artifactId>codion-swing-framework-ui</artifactId>
<version>0.18.38</version>
</dependency>
# Or your Gradle project
implementation 'is.codion:codion-swing-framework-ui:0.18.38'
Next steps:
- Try the Petclinic demo - Basic CRUD patterns
- Explore the manual - Deep dive into concepts
- Check the World demo - Advanced domain modeling
- Study Chinook - Kitchen sink example
📜 License: Open Source, Commercially Friendly
GPL-3.0 with Commercial Linking Exception
- ✅ Free for open source projects and internal use
- ✅ Commercial licensing available for closed-source distribution, Q1 2026.
- ✅ No vendor lock-in - you own your code
- ✅ No per-user fees or runtime royalties
Codion: The framework you wish you’d found years ago.
Battle-tested by 20 years and 50+ production applications. Ready for the next 20.