5 Patterns That Make qqq Different From Other Frameworks
What sets qqq apart from Spring Boot, Django, and Rails? These five architectural patterns explain why teams ship faster with qqq.

When developers first look at qqq, they often compare it to frameworks they know: Spring Boot, Django, Rails. But qqq isn't just another MVC framework. It's built on fundamentally different patterns that change how you think about building applications.
Most frameworks make you choose between speed and flexibility. qqq's metadata-driven architecture gives you both by separating what your app does from how it does it.
Here are five patterns that make qqq unique.
Pattern 1: Metadata as Source of Truth
In traditional frameworks, you write code and the framework runs it. In qqq, you describe your application using metadata, and the framework generates the code.
new QTableMetaData()
.withName("order")
.withFields(List.of(
new QFieldMetaData("id", QFieldType.INTEGER).withIsPrimaryKey(true),
new QFieldMetaData("customerId", QFieldType.INTEGER).withIsRequired(true),
new QFieldMetaData("status", QFieldType.STRING)
))
.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.RECORD));This single definition gives you: a database table, CRUD operations, REST endpoints, validation, audit logging, and admin UI. The metadata is the source of truth; everything else derives from it.
Pattern 2: Backend Agnostic Data Layer
qqq doesn't just support multiple databases - it abstracts the entire backend layer. Your application code works the same whether data lives in PostgreSQL, MongoDB, a REST API, or a flat file.
// Same query code works against any backend
QQueryFilter filter = new QQueryFilter()
.withCriteria(new QFilterCriteria("status", QCriteriaOperator.EQUALS, "pending"));
QueryOutput output = new QueryAction()
.execute(new QueryInput().withTableName("order").withFilter(filter));Switch from MySQL to PostgreSQL? Change one configuration line. Add a legacy REST API as a data source? Same query syntax.
Pattern 3: Composable Actions
Every operation in qqq is an Action - a composable unit that can be extended, wrapped, or replaced. Want to add custom validation? Wrap the InsertAction. Need audit logging? It's already built in.
Actions follow a consistent pattern: Input -> Action -> Output. This makes them easy to test, easy to extend, and easy to understand.
Pattern 4: Progressive Enhancement
Start with generated code and UI. As requirements grow, progressively add custom behavior. Override a single field's validation while keeping everything else generated. Add a custom REST endpoint alongside the generated ones.
You're never forced into an all-or-nothing choice. Customize what you need; let the framework handle the rest.
Pattern 5: Full Code Ownership
Here's where qqq differs from low-code platforms: when you need custom behavior, you drop down to regular Java. No proprietary scripting language, no limitations.
The generated code isn't hidden in a black box - it's your code. Fork it, modify it, deploy it anywhere. Apache 2.0 licensing ensures this freedom with no strings attached.
Why These Patterns Matter
These patterns compound. Metadata-first means less code to maintain. Backend abstraction means portability. Composable actions mean extensibility. Progressive enhancement means no limitations. Code ownership means no lock-in.
The result: teams consistently report building in days what would take weeks with traditional frameworks.
Ready to try it? Start with our 90-second quickstart or dive into the documentation.