Getting Started with qqq: Your First App in 30 Minutes
Learn how to build a complete CRUD application with authentication, audit trails, and a dashboard in under 30 minutes using the qqq framework.

This tutorial walks you through building a complete application with qqq. By the end, you'll have a working app with CRUD operations, a REST API, authentication, and an admin UI.
The qqq framework allows you to define your entire application through metadata, eliminating the need for boilerplate code while maintaining full control over your business logic.
Prerequisites
You'll need:
- Java 21 or later
- Maven 3.8+
- Your favorite IDE (IntelliJ recommended)
Step 1: Create Your Project
Start with our Maven archetype:
mvn archetype:generate \
-DarchetypeGroupId=io.qrun \
-DarchetypeArtifactId=qqq-quickstart \
-DgroupId=com.example \
-DartifactId=my-appThis creates a project with qqq dependencies configured and a sample application structure.
Step 2: Define Your First Table
Create a table for customers. In src/main/java/com/example/metadata/CustomerTableMetaData.java:
public class CustomerTableMetaData implements MetaDataProducerInterface<QTableMetaData> {
public static final String TABLE_NAME = "customer";
@Override
public QTableMetaData produce(QInstance qInstance) {
return new QTableMetaData()
.withName(TABLE_NAME)
.withBackendName("default")
.withPrimaryKeyField("id")
.withFields(List.of(
new QFieldMetaData("id", QFieldType.INTEGER),
new QFieldMetaData("name", QFieldType.STRING)
.withIsRequired(true)
.withMaxLength(100),
new QFieldMetaData("email", QFieldType.STRING)
.withIsRequired(true),
new QFieldMetaData("createdAt", QFieldType.DATE_TIME)
));
}
}That's it. This single class gives you:
- Database table creation
- Insert, update, delete, and query operations
- REST API endpoints (
/api/customer) - OpenAPI documentation
- Admin UI with search, forms, and validation
Step 3: Add Another Table with Relationships
Add an orders table that links to customers:
public class OrderTableMetaData implements MetaDataProducerInterface<QTableMetaData> {
public static final String TABLE_NAME = "order";
@Override
public QTableMetaData produce(QInstance qInstance) {
return new QTableMetaData()
.withName(TABLE_NAME)
.withBackendName("default")
.withPrimaryKeyField("id")
.withFields(List.of(
new QFieldMetaData("id", QFieldType.INTEGER),
new QFieldMetaData("customerId", QFieldType.INTEGER)
.withIsRequired(true),
new QFieldMetaData("orderDate", QFieldType.DATE),
new QFieldMetaData("total", QFieldType.DECIMAL),
new QFieldMetaData("status", QFieldType.STRING)
.withPossibleValueSourceName("orderStatus")
))
.withRecordSecurityLock(new QRecordSecurityLock()
.withFieldName("customerId"));
}
}Step 4: Configure Your Backend
In your application configuration, set up a database:
qInstance.addBackend(new QBackendMetaData()
.withName("default")
.withBackendType("RDBMS")
.withConnection(new DatabaseConnection()
.withDatabaseType(DatabaseType.POSTGRESQL)
.withJdbcUrl("jdbc:postgresql://localhost:5432/myapp")
.withUsername("myuser")
.withPassword("mypassword")
)
);qqq supports PostgreSQL, MySQL, SQLite, MongoDB, and custom backends. Switch databases by changing the connection - your application code stays the same.
Step 5: Add Authentication
Enable authentication with a few lines:
qInstance.withAuthentication(new QAuthenticationMetaData()
.withType(QAuthenticationType.TABLE_BASED)
.withUserTableName("user")
);This adds login/logout, session management, and user management. For OAuth2 or SAML, use the appropriate authentication type.
Step 6: Enable Audit Logging
Add audit trails to track all changes:
// On your table definition
.withAuditRules(new QAuditRules()
.withAuditLevel(AuditLevel.RECORD))Every insert, update, and delete is now logged with who made the change and when.
Step 7: Run Your Application
Start the development server:
mvn compile exec:javaOpen http://localhost:8000 to see your admin UI. Navigate to customers, create a few records, then check the audit log to see your changes tracked.
What You've Built
In about 30 minutes and ~100 lines of code, you have:
- Two database tables with a relationship
- Full CRUD operations for both
- REST API with OpenAPI documentation
- Admin UI with forms, search, and validation
- User authentication
- Audit logging for compliance
With traditional frameworks, this would require several thousand lines of code across dozens of files.
Next Steps
From here, you can:
- Add business logic: Create processes with custom steps
- Configure permissions: Set up role-based access control
- Customize the UI: Override generated components
- Deploy to production: Use qRun or self-host
Check out our documentation for deep dives on each topic, or try our weekend project tutorial to build a complete order management system.
Getting Help
- Join our Discord community for real-time help
- Browse the GitHub repository for examples
- Read the FAQ for common questions
Welcome to qqq. We can't wait to see what you build.