Database

Obsidian uses its own native ORM and HikariCP for connection pooling. The connection is managed automatically — no manual wrapping required.

Supported databases
Database DB_TYPE Notes
SQLite sqlite File-based, no pooling. Perfect for development and small apps.
MySQL mysql HikariCP connection pooling included. SSL enabled by default.
PostgreSQL postgresql HikariCP connection pooling included. SSL enabled by default.
Environment configuration

Obsidian uses dotenv-java to load credentials from a .env file at your project root.

SQLite
ENVIRONMENT=development
PORT_WEB=8080

DB_TYPE=sqlite
DB_PATH=database.db
MySQL
ENVIRONMENT=development
PORT_WEB=8080

DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_NAME=my_database
DB_USER=root
DB_PASSWORD=secret
PostgreSQL
ENVIRONMENT=development
PORT_WEB=8080

DB_TYPE=postgresql
DB_HOST=localhost
DB_PORT=5432
DB_NAME=my_database
DB_USER=postgres
DB_PASSWORD=secret
Security warning
Never commit your .env file to version control. Add it to .gitignore.
SSL (MySQL / PostgreSQL)

SSL is enabled by default for MySQL and PostgreSQL. In local dev or test environments where your server has no certificate, disable it via an environment variable or a JVM system property.

Environment variable
OBSIDIAN_DB_DISABLE_SSL=true
JVM system property (takes priority)
-DOBSIDIAN_DB_DISABLE_SSL=true
exec-maven-plugin in pom.xml
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <configuration>
        <systemProperties>
            <systemProperty>
                <key>OBSIDIAN_DB_DISABLE_SSL</key>
                <value>true</value>
            </systemProperty>
        </systemProperties>
    </configuration>
</plugin>
Never disable SSL in production.
A warning is logged every time this flag is active.
Automatic connection management

The framework automatically opens and closes the thread-local connection around every HTTP request via two built-in middlewares — DatabaseMiddleware and DatabaseCloseMiddleware. You never need to manage connections manually in controllers or repositories.

When running database queries outside of an HTTP request (e.g. in a LiveComponent or a background task), wrap the call with DB.withConnection():

List<UserDTO> users = DB.withConnection(() ->
    userService.findAll().stream().toList()
);
Transactions

Use DB.withTransaction() for atomic operations. Changes are committed on success and rolled back on any exception.

DB.withTransaction(() -> {
    User sender   = Model.find(User.class, senderId);
    User receiver = Model.find(User.class, receiverId);

    if (sender.getBigDecimal("balance").compareTo(amount) < 0) {
        throw new IllegalStateException("Insufficient balance");
    }

    sender.set("balance", sender.getBigDecimal("balance").subtract(amount));
    receiver.set("balance", receiver.getBigDecimal("balance").add(amount));

    sender.save();
    receiver.save();

    return true;
});
Connection pool (MySQL / PostgreSQL)

HikariCP is automatically configured with these defaults:

Maximum pool size 20 connections
Minimum idle 5 connections
Connection timeout 30 seconds
Idle timeout 10 minutes
Max lifetime 30 minutes

SQLite uses direct JDBC connections without pooling.