Sqlx4k
A coroutine-first SQL toolkit with compile-time query validations for Kotlin Multiplatform. PostgreSQL, MySQL/MariaDB, and SQLite supported.
Install / Use
/learn @smyrgeorge/Sqlx4kREADME
sqlx4k
A coroutine-first SQL toolkit with compile-time query validations for Kotlin Multiplatform. PostgreSQL, MySQL/MariaDB, and SQLite supported.
sqlx4k is not an ORM. Instead, it provides a comprehensive toolkit of primitives and utilities to communicate directly with your database. The focus is on giving you control while catching errors early through compile-time query validation—preventing runtime surprises before they happen (see SQL syntax validation (compile-time) and SQL schema validation (compile-time) for more details).
The library is designed to be extensible, with a growing ecosystem of tools and extensions like PGMQ (PostgreSQL Message Queue), SQLDelight integration, and more.
🏠 Homepage (under construction)
📰 Articles
Short deep‑dive posts covering Kotlin/Native, FFI, and Rust ↔ Kotlin interop used in sqlx4k:
- Introduction to the Kotlin Native and FFI: [Part 1], [Part 2]
- Interoperability between Kotlin and Rust, using FFI: [Part 1], (Part 2 soon)
Features
- Supported databases
- Async I/O
- Connection pool and settings
- Acquiring and using connections
- Running queries
- Prepared statements (named and positional parameters)
- Row mappers
- Custom Value Converters
- Transactions and coroutine TransactionContext · TransactionContext (coroutines)
- Code generation: CRUD and @Repository implementations
- Database migrations
- PostgreSQL LISTEN/NOTIFY
- Extensions
- Supported targets
Next Steps (contributions are welcome)
- Create and publish sqlx4k-gradle-plugin
- Support streaming large tables (e.g. with cursors)
- Validate queries at compile time (avoid runtime errors)
- Syntax checking is already supported (using the
@Queryannotation) ✅ - Validate queries by accessing the DB schema ✅
- Validate query literal types (type check query parameters)
- Syntax checking is already supported (using the
- Add support for SQLite JVM target ✅
- WASM support (?).
Supported Databases
Async-io
The driver is designed with full support for non-blocking I/O, enabling seamless integration with modern, high-performance applications. By leveraging asynchronous, non-blocking operations, it ensures efficient resource management, reduces latency, and improves scalability.
Connection Pool
Connection Pool Settings
The driver allows you to configure connection pool settings directly from its constructor, giving you fine-grained control over how database connections are managed. These settings are designed to optimize performance and resource utilization for your specific application requirements.
Key Configuration Options:
-
minConnections
Specifies the minimum number of connections to maintain in the pool at all times. This ensures that a baseline number of connections are always ready to serve requests, reducing the latency for acquiring connections during peak usage. -
maxConnections
Defines the maximum number of connections that can be maintained in the pool. This setting helps limit resource usage and ensures the pool does not exceed the available database or system capacity. -
acquireTimeout
Sets the maximum duration to wait when attempting to acquire a connection from the pool. If a connection cannot be acquired within this time, an exception is thrown, allowing you to handle connection timeouts gracefully. -
idleTimeout
Specifies the maximum duration a connection can remain idle before being closed and removed from the pool. This helps clean up unused connections, freeing up resources. -
maxLifetime
Defines the maximum lifetime for individual connections. Once a connection reaches this duration, it is closed and replaced, even if it is active, helping prevent issues related to stale or long-lived connections.
By adjusting these parameters, you can fine-tune the driver's behavior to match the specific needs of your application, whether you're optimizing for low-latency responses, high-throughput workloads, or efficient resource utilization.
// Additionally, you can set minConnections, acquireTimeout, idleTimeout, etc.
val options = Driver.Pool.Options.builder()
.maxConnections(10)
.build()
/**
* The following urls are supported:
* postgresql://
* postgresql://localhost
* postgresql://localhost:5433
* postgresql://localhost/mydb
*
* Additionally, you can use the `postgreSQL` function, if you are working in a multiplatform setup.
*/
val db = PostgreSQL(
url = "postgresql://localhost:15432/test",
username = "postgres",
password = "postgres",
options = options
)
/**
* The connection URL should follow the nex pattern,
* as described by [MySQL](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html).
* The generic format of the connection URL:
* mysql://[host][/database][?properties]
*/
val db = MySQL(
url = "mysql://localhost:13306/test",
username = "mysql",
password = "mysql"
)
/**
* The following urls are supported:
* `sqlite::memory:` | Open an in-memory database.
* `sqlite:data.db` | Open the file `data.db` in the current directory.
* `sqlite://data.db` | Open the file `data.db` in the current directory.
* `sqlite:///data.db` | Open the file `data.db` from the root (`/`) directory.
* `sqlite://data.db?mode=ro` | Open the file `data.db` for read-only access.
*/
val db = SQLite(
url = "sqlite://test.db", // If the `test.db` file is not found, a new db will be created.
options = options
)
Acquiring and using connections
The driver provides two complementary ways to run queries:
- Directly through the database instance (recommended). Each call acquires a pooled connection, executes the work, and returns it to the pool automatically.
- Manually acquire a connection from the pool when you need to batch multiple operations on the same connection without starting a transaction.
Notes:
- When you manually acquire a connection, you must release it to return it to the pool.
Examples (PostgreSQL shown, similar to MySQL/SQLite):
// Manual connection acquisition (remember to release)
val conn: Connection = db.acquire().getOrThrow()
try {
conn.execute("insert into users(id, name) values (2, 'Bob');").getOrThrow()
val rs = conn.fetchAll("select * from users;").getOrThrow()
// ...
} finally {
conn.close().getOrThrow() // Return to pool
}
Setting Transaction Isolation Level
You can set the transaction isolation level on a connection to control the degree of visibility between concurrent transactions.
val conn: Connection = db.acquire().getOrThrow()
// Set the isolation level before starting operations
conn.setTransactionIsolationLevel(Transaction.IsolationLevel.Serializable).getOrThrow()
Running Queries
All database interactions go through the QueryExecutor interface, which provides a consistent, coroutine-based API for executing SQL statements. This interface is implemented by:
- Database drivers (
PostgreSQL,MySQL,SQLite) - for dire
Related Skills
oracle
339.3kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
prose
339.3kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
Command Development
83.9kThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
Plugin Structure
83.9kThis skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure", "organize plugin components", "set up plugin.json", "use ${CLAUDE_PLUGIN_ROOT}", "add commands/agents/skills/hooks", "configure auto-discovery", or needs guidance on plugin directory layout, manifest configuration, component organization, file naming conventions, or Claude Code plugin architecture best practices.
