sqlitebp provides an opinionated, production-ready configuration for SQLite databases in Go applications. It implements SQLite best practices with sensible defaults focused on safety, performance, and reliability.
go get github.com/jacob2161/sqlitebppackage main
import (
"fmt"
"log"
"github.com/jacob2161/sqlitebp"
)
func main() {
// Creates or opens the database with best-practice defaults
// (WAL, foreign keys, busy timeout, NORMAL synchronous, private cache, etc.)
db, err := sqlitebp.OpenReadWriteCreate("app.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Create a table (STRICT for stronger type enforcement)
if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL) STRICT`); err != nil {
log.Fatal(err)
}
// Insert a row
if _, err := db.Exec(`INSERT INTO users (name) VALUES (?)`, "Alice"); err != nil {
log.Fatal(err)
}
// Query a value
var count int
if err := db.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&count); err != nil {
log.Fatal(err)
}
fmt.Println("User rows:", count)
}db, err := sqlitebp.OpenReadWrite("app.db")
if err != nil {
log.Fatal(err)
}
// e.g. read previously inserted rows
var n int
if err := db.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&n); err != nil {
log.Fatal(err)
}db, err := sqlitebp.OpenReadOnly("app.db")
if err != nil {
log.Fatal(err)
}
var n int
if err := db.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&n); err != nil {
log.Fatal(err)
}// Increase busy timeout (seconds), enlarge cache, enforce FULL synchronous
db, err := sqlitebp.OpenReadWriteCreate("app.db",
sqlitebp.WithBusyTimeoutSeconds(30),
sqlitebp.WithCacheSizeMiB(64),
sqlitebp.WithSynchronous("FULL"),
)
if err != nil {
log.Fatal(err)
}// Use DELETE journal instead of WAL
db, err := sqlitebp.OpenReadWriteCreate("app.db",
sqlitebp.WithJournalMode("DELETE"),
)
if err != nil {
log.Fatal(err)
}// Force temporary tables to disk instead of memory (trade performance for lower RAM)
db, err := sqlitebp.OpenReadWriteCreate("app.db",
sqlitebp.WithTempStore("FILE"),
)
if err != nil {
log.Fatal(err)
}// Disable automatic PRAGMA optimize on new connections
// (Enabled by default unless explicitly disabled)
db, err := sqlitebp.OpenReadWriteCreate("app.db",
sqlitebp.WithOptimize(false),
)
if err != nil {
log.Fatal(err)
}By default, sqlitebp sets the pool size to a sensible value between 2 and 8 based on GOMAXPROCS. You can override this after opening if you need a single serialized connection, or just rely on the defaults for read‑only access.
// Single-connection (serialized) read/write/create database
rwdb, err := sqlitebp.OpenReadWriteCreate("app.db")
if err != nil {
log.Fatal(err)
}
// Force a single connection in the pool
rwdb.SetMaxOpenConns(1)
rwdb.SetMaxIdleConns(1)// Read-only with default adaptive pool size (2-8 based on GOMAXPROCS)
rodb, err := sqlitebp.OpenReadOnly("app.db")
if err != nil {
log.Fatal(err)
}(Shared cache is intentionally not supported; private cache is enforced to avoid shared-cache pitfalls.)
The package applies these SQLite best practices automatically:
- WAL Mode (
_journal_mode=WAL) except in read-only mode (journal not forced when read-only) - Foreign Keys Enabled (
_foreign_keys=true) - Busy Timeout (
_busy_timeout=10000ms) - Private Cache enforced (
cache=private) - not user configurable - Synchronous NORMAL (
_synchronous=NORMAL) - Page Cache 32 MiB (
_cache_size=-32768KB) - Smart Connection Pool (2-8 connections based on GOMAXPROCS)
- PRAGMA optimize on each connection (disable via
WithOptimize(false)) - Temp Storage in Memory by default (
PRAGMA temp_store=MEMORY) - overridable viaWithTempStore
Optimized and tested for Linux. Other platforms may work but are not a focus.
- Base page cache: ~32 MiB (configurable via
WithCacheSizeMiB) - Temp tables & sorts: additional RAM depending on workload (switch to FILE via
WithTempStore("FILE")if needed)
- Creates database if it doesn't exist
- Full read/write, all optimizations
- Database must exist
- Full read/write
- Database must exist
- No writes
- Existing journal mode respected (WAL not forced)
- Other optimizations still applied (foreign keys, busy timeout unaffected)
Run tests:
go test -vMIT. See LICENSE
PRs welcome that improve safety, correctness, or performance.