Pure-Go CGO-free SQLite client with launcher lifecycle, write-mutex serialisation, health check, unit-of-work via context injection, and structured error mapping. What's included: - Executor / Tx / Client / Component interfaces using database/sql native types - Tx.Commit() / Tx.Rollback() without ctx, matching the honest database/sql contract - New(logger, cfg) constructor; database opened in OnInit - Config struct with env-tag support; default Pragmas: WAL + 5s busy timeout + FK enforcement - PRAGMA foreign_keys = ON enforced explicitly in OnInit - writeMu sync.Mutex acquired by UnitOfWork.Do to serialise writes and prevent SQLITE_BUSY - UnitOfWork via context injection; GetExecutor(ctx) returns active Tx or *sql.DB - HandleError mapping SQLite extended error codes to xerrors codes (unique/primary-key → AlreadyExists, foreign-key → InvalidInput, ErrNoRows → NotFound) - health.Checkable at LevelCritical; pure-Go modernc.org/sqlite driver (CGO_ENABLED=0 compatible) Tested-via: todo-api POC integration Reviewed-against: docs/adr/
1.6 KiB
1.6 KiB
ADR-001: Pure-Go SQLite Driver via modernc.org/sqlite
Status: Accepted Date: 2026-03-18
Context
SQLite requires a C library on the host system. The standard mattn/go-sqlite3 driver wraps the
C library via cgo. This means:
- CGO must be enabled at build time (
CGO_ENABLED=1). - A C toolchain must be present in every build and CI environment.
- Cross-compilation is significantly harder (requires a cross-compiling C toolchain).
- Static binaries are complicated to produce without additional linker flags.
For a micro-lib that should work in minimal container environments and cross-compile without ceremony, this is a poor baseline.
Decision
Use modernc.org/sqlite as the SQLite driver. This is a transpilation of the official SQLite
amalgamation from C to Go, producing a pure-Go implementation with no CGO dependency. It is
registered under the driver name "sqlite" and is otherwise compatible with database/sql.
The import is a blank import in sqlite.go:
import _ "modernc.org/sqlite" // register sqlite driver
Consequences
Positive:
CGO_ENABLED=0builds work out of the box.- Cross-compilation requires no special toolchain setup.
- CI environments need only the Go toolchain.
- Minimal container images (scratch, distroless) are straightforward targets.
Negative:
modernc.org/sqlitelags slightly behind the official SQLite release cadence.- Transpiled code is harder to debug at the C level than
mattn/go-sqlite3. - The driver name is
"sqlite"not"sqlite3", which would conflict with any project that also importsmattn/go-sqlite3.