Files
sqlite/docs/adr/ADR-001-modernc-pure-go-driver.md
Rene Nochebuena 237cba9bad feat(sqlite): initial stable release v0.9.0
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/
2026-03-19 13:25:31 +00:00

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=0 builds 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/sqlite lags 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 imports mattn/go-sqlite3.