GitHub - go-again/sqlite: CGo-free SQLite driver for Go
The comprehensive, AI-ready, CGo-free SQLite stack for Go. One module replaces mattn/go-sqlite3 (registers as "sqlite3"), modernc.org/sqlite ("sqlite"), and the glebarez/sqlite gorm dialector — then adds first-class typed APIs for vector search, full-text search, encryption at rest, in-memory MVCC, hybrid ranking, a user-implementable VFS, a bounded page cache, and a catalog of loadable SQL extensions. Designed so that migrating to CGo-free and adopting advanced SQLite features is a one-line change, and so your AI coding agent gets it right the first time — the repo ships Agent Skills that teach assistants the real API. All pure Go.
import sqlite "gosqlite.org" db, _ := sqlite.OpenWAL("app.db") // WAL + busy_timeout=5s + foreign_keys=on defer db.Close() // db embeds *sql.DB — every database/sql method works.
Existing mattn / modernc / glebarez / ncruces code keeps working after the import swap; the legacy sql.Open("sqlite3", "file:...?_pragma=…") form is still accepted. Your ORM works too — LiteORM is built on this driver, the gorm dialector is a companion module (gosqlite.org/gorm), and xorm uses the driver as-is. See the migration guide.
Why gosqlite
-
🤖 AI / LLM-ready — your coding agent writes correct code on the first try. The repo ships Agent Skills: task-scoped instructions (vector search, FTS5, the gorm dialector, LiteORM, custom VFS, migration, pitfalls) an AI assistant loads on demand, so it reaches for the real API instead of hallucinating one — drop
skills/into your agent and the trial-and-error loop largely disappears. It's backed by structured, task-oriented docs ("I want X → do Y"), anAGENTS.mdfor agents working in the codebase, anddoc.goon every package for pkg.go.dev. This is the fastest way to build on SQLite with an AI pair-programmer. -
📦 Comprehensive — the whole stack, one project. Driver + typed sqlite-vec + FTS5 + rank fusion + checksums + in-memory & custom VFSes + a bounded page cache + the
ext/catalog all ship and version together in the coregosqlite.orgmodule; encryption (vfs/crypto), a secure container with compression + encryption (vfs/vault), blob storage (blobstore), and the gorm dialector (gosqlite.org/gorm) are opt-in companion modules in the same repo on the same release cadence, so the core stays dependency-free for everyone who doesn't use them. No stitchingmodernc.org/sqlite+glebarez/sqlite+asg017/sqlite-vec+ a separate encryption/vtab module and reconciling four release cadences — and your agent reasons about one surface, not four. -
🔀 CGo-free migration in one line. Swap the import; keep your
sql.Open("sqlite3", …)calls and_*DSN flags (translated transparently). Two driver names ("sqlite"+"sqlite3") mean code from either lineage compiles unchanged. You drop the C toolchain, cross-compile with plainGOOS=… go build, and ship static distroless/alpine binaries. -
⚡ Advanced SQLite features without the DIY plumbing. Vector + full-text search, encryption at rest, a writable custom VFS, sessions/changesets, custom Go FTS5 tokenizers, a bounded page cache — typed and first-class here, where every other Go SQLite driver makes you build them yourself (or doesn't offer them at all). Want that search inside an ORM? LiteORM layers declarative
vec:/fts:model tags on top of this driver —AutoMigrateprovisions the sidecars, typed helpers return ranked results.
Documentation
- gosqlite.com — the documentation site. Start at gosqlite.com/docs (Getting started · Guides · Extensions).
- pkg.go.dev/gosqlite.org — the Go API reference.
- Browsing the repo directly? The same docs live under
docs/— Getting started · Guides · Extensions. skills/— task recipes for AI agents using the package;AGENTS.mdfor agents developing it.
What you get
The driver itself — CGo-free, mattn-API + glebarez-gorm drop-in, registered under both "sqlite" and "sqlite3" — is just the floor. Stacked on top:
- Vector search — typed
vec.Tableover sqlite-vec: L2 / Cosine / Dot / Hamming, JSON + binary + quantizedint8/bitencodings, metadata / partition / auxiliary columns, streamingiter.Seq2KNN, predicate pushdown. - Full-text search — typed
fts.Index[K, V]over FTS5: Porter / Unicode61 / Trigram tokenizers plus custom Go tokenizers, a Go query builder, BM25 ranking, snippet + highlight. - Hybrid search —
fusion.RRFcombinesvec.KNNandfts.Searchrankings via Reciprocal Rank Fusion. - Encryption at rest — pure-Go
vfs/crypto(a separate module), Adiantum or AES-XTS-256, transparent page-level encryption of DB + journal + WAL + temp;crypto.Openfor one-call typed-Config setup; Argon2id key derivation; per-IO observability. For multiple recipients (each opens with their own key, no shared secret), crash-safe key rotation, and tamper-evident storage (per-page integrity + a signed root), reach forvfs/vault— a container where compression and encryption are independent options. - Corruption detection — pure-Go
vfs/cksm, Fletcher-style trailer per page (compatible with SQLite'scksumvfs); composes beneathvfs/crypto. - In-memory & embedded —
vfs/mvcc(snapshot isolation) andvfs/memdb(direct), plusvfs.New(fs.FS)/vfs.NewReaderforembed.FSand raw-buffer databases. - User-implementable VFS — back a writable database with arbitrary Go storage via
vfs.Register+ thevfs.VFS/vfs.Fileinterfaces; WAL via the optionalvfs.ShmFile;vfs.Wrapinstrumentation. - Bounded page cache —
pcache.InstallBoundedLRU(maxPages)bounds SQLite's page-cache heap with hit / miss / eviction / live-page counters. - Loadable Go SQL extensions under
ext/— scalars / aggregates / collations (regexp,uuid,hash,stats,unicode,fuzzy,decimal,money,time,eval, …), virtual tables (array,csv,lines,rtree,series, …), stores (bloom,spellfix1), I/O (blobio,fileio) — many with a typed Go handle. Auto-register per conn or pool-wide. - Sessions / changesets — record changes into a changeset/patchset,
ApplyChangesetto a replica,InvertChangeset,ConcatChangesets. Offline sync, audit logs, replication — no other pure-Go SQLite driver exposes this. - Hooks, backup & introspection — per-conn update / authorizer / commit / trace hooks,
Backup+Serialize/Deserialize, column metadata + runtime telemetry, the*FunctionContextaux-data substrate. - Modern Go-typed Config —
sqlite.Config{Path, Pragmas, …}flows uniformly to rawdatabase/sql, gorm, andcrypto.Open; plus typed pragma enums and one-line open shortcuts. - sqlitex ergonomics —
Save,Transaction,Execute, scalar reads, and anembed.FSmigration runner. - Blob storage — pure-Go
blobstore(a separate module) keeps a large, growable byte object (files, uploads, streamed content) as anio.ReaderAt/io.WriterAt, O(chunk) memory, with sparse holes, truncate, optional transparent per-object compression, and refcounted copy-on-write blocks for cheap clones, versions/snapshots, and optional dedup. - Secure compressed container — pure-Go
vfs/vault(a separate module), a block-structured container where compression and encryption are independent options (plain, compressed, encrypted, or both).vault.Openqueries the database in place — a live, file-backed storage engine, durable per transaction, multi-connection, WAL-capable, that never writes a weaker form than configured to disk. On top of compression: single-key or multi-recipient encryption (each party opens with their own key, no shared secret), crash-safe key rotation, admin-only membership enumeration (vault.Members), tamper-evident storage (symmetric MAC or ed25519-signed root), optional rollback resistance via an external anchor, encrypted backups to a new path (vault.Snapshot), and space reclaim both offline (Compact) and online (Trim); a segmented page directory keeps each commit O(changed pages) so it stays flat as the image grows — plusvault.OpenSnapshot/Pack/Unpackfor shipping. No other pure-Go SQLite driver ships this.
Declarative models with native search: LiteORM
Want declarative models on top of all this? LiteORM integrates with this driver more deeply than any other Go SQLite stack: its vector, full-text, and hybrid (RRF) search are built directly on this driver's vec / fts / fusion packages, and encryption rides on vfs/crypto — search isn't bolted on, it's the same engine.
- Declare, don't wire. Put
vec:/fts:tags (or aSearchIndexes()method) on a model;AutoMigrateprovisions the FTS5 + vec0 sidecars and keeps them in sync on every write. - Typed, ranked results.
search.For[T](db).Vector / .FullText / .Hybridreturn your models in score order — no manual KNN SQL. - Same driver, no walls. Open with the same
gosqlite.Config; gosqlite'sext/SQL functions work through the query builder with no glue (e.g.REGEXPviasqlite.WhereRegex, which range-scans an index for left-anchored patterns); andsqlite.Conn(db)hands back the raw*gosqlite.DBfor sessions, backup, or the typedvec/ftshandles anytime.
It's a separate module (liteorm.org), so the gosqlite core stays dependency-free. Runnable end-to-end demo: examples/liteorm/; agent recipe: skills/liteorm. (For gorm.io/gorm specifically, the gosqlite.org/gorm dialector is the drop-in — it covers the dialector contract; ORM-level search is its domain.)
How it compares
The Go SQLite landscape has three camps: CGo bindings (mattn, zombiezen), pure-Go ccgo transpilation (modernc, this, glebarez), and pure-Go via WebAssembly + wazero (ncruces). Where this module sits:
| Capability | this | mattn | modernc | ncruces | glebarez |
|---|---|---|---|---|---|
| Ships AI Agent Skills + task-oriented docs | ✓ | ✗ | ✗ | ✗ | ✗ |
| Whole stack (driver + vec + FTS5 + fusion + VFS + ext) in one module | ✓ | ✗ | ✗ | ✗ | ✗ |
| CGo-free | ✓ | ✗ | ✓ | ✓ (wazero) | ✓ |
Builds in distroless / golang:alpine, no apk add |
✓ | ✗ | ✓ | ✓ | ✓ |
database/sql driver |
✓ | ✓ | ✓ | ✓ | ✗ (gorm only) |
Registers as both "sqlite" and "sqlite3" |
✓ | ✗ | ✗ | ✗ | n/a |
Mattn-compat surface (hooks, Backup, Serialize, …) |
✓ | n/a | partial | partial | n/a |
| ORM with native vector / FTS / hybrid search (via LiteORM) | ✓ | ✗ | ✗ | ✗ | ✗ |
| CGo-free gorm dialector (companion module) | ✓ | ✗ | ✗ | ✗ | ✓ |
| Typed sqlite-vec API | ✓ | ✗ | ✗ | ✗ | ✗ |
| Typed FTS5 API + custom Go tokenizers | ✓ | ✗ | ✗ | ✗ | ✗ |
| Hybrid-search rank fusion | ✓ | ✗ | ✗ | ✗ | ✗ |
| Encryption-at-rest VFS | ✓ (Adiantum + AES-XTS, one constructor) | ✗ | ✗ | ✓ (two packages) | ✗ |
| Compressed-at-rest database (live, queried in place, pure Go) | ✓ | ✗ | ✗ | ✗ | ✗ |
Page-checksum / in-memory / fs.FS VFSes |
✓ | ✗ | ✗ | ✓ | ✗ |
| User-implementable VFS (pure Go) | ✓ (rollback-journal + WAL via ShmFile) |
✗ | ✗ | ✓ | ✗ |
| Bounded / observable page cache (pure Go) | ✓ | ✗ | ✗ | ✗ | ✗ |
| Changesets / session sync | ✓ | ✗ | ✗ | ✗ | ✗ |
| Loadable Go SQL extensions | catalog under ext/ |
math/regexp via build-tag | ✗ | similar catalog | ✗ |
| Hot UDF-row throughput | == modernc | fastest (CGo) | baseline | slowest (wazero) | == modernc |
Better here: it's the only Go SQLite package that ships AI Agent Skills + task-oriented docs, so an AI assistant builds against it correctly without trial and error; one project ships the whole stack (driver + vec + FTS5 + fusion + cksm + VFSes + page cache + ext/, plus the vfs/crypto, vfs/vault, blobstore, and gorm companion modules) on one release cadence; one driver under two SQL names makes migration a one-line swap; typed vec/FTS5 are first-class where every other driver needs DIY plumbing; custom Go FTS5 tokenizers and the typed sqlite.Config are unique to this module; and LiteORM, built on this driver, is the only Go SQLite data layer with native vector / full-text / hybrid search wired straight in.
The trade-offs are narrow: mattn's CGo binding is ~3% faster on hot per-row UDF paths (a few extra allocs/op on a no-op authorizer — invisible once you let SQL do the work); the support window tracks the two newest Go releases; and vfs/crypto is confidentiality-only (no SQLCipher on-disk format or per-page MAC). None is a dealbreaker for typical use; details in Performance.
Quick start
import sqlite "gosqlite.org" // One-line presets, no DSN string: db, _ := sqlite.OpenWAL("app.db") // production: WAL + busy_timeout + foreign_keys mem, _ := sqlite.OpenInMemory() // tests / scratch // Or the typed Config (pragmas, encryption, pool tuning in one value): db2, _ := sqlite.Open(sqlite.Config{ Path: "myapp.db", Pragmas: sqlite.RecommendedPragmas(), MaxOpenConns: 8, })
Plain database/sql works too: sql.Open("sqlite", "file:app.db"). The full setup story — open shortcuts, the typed Config, typed pragma enums — is in Configuration; start-to-finish in Getting started.
Packages
| Import path | What it gives you |
|---|---|
gosqlite.org |
the driver (registers "sqlite" + "sqlite3") + Config + hooks + backup/serialize |
gosqlite.org/gorm |
gorm.Dialector drop-in (glebarez / go-gorm) — separate module |
gosqlite.org/vec |
typed sqlite-vec Table (L2 / Cosine / Dot / Hamming, quantized encodings) |
gosqlite.org/fts |
typed FTS5 Index[K, V] + custom Go tokenizers |
gosqlite.org/fusion |
RRF rank-fusion helpers (combine vec + fts results) |
gosqlite.org/vfs (+ cksm, mvcc, memdb) |
fs.FS/io.ReaderAt adapters, the user-implementable VFS, checksums, in-memory |
gosqlite.org/vfs/crypto |
Adiantum / AES-XTS-256 encryption-at-rest VFS + crypto.Open, single raw key (confidentiality only) — separate module |
gosqlite.org/crypto/keyring |
wrap a database's data key for multiple recipients (SSH keys / passphrases / age) so several parties open one encrypted database — separate module |
gosqlite.org/pcache |
application-controlled bounded page cache |
gosqlite.org/sqlitex |
ergonomic database/sql helpers + embed.FS migrations |
gosqlite.org/blobstore |
large, growable byte objects as io.ReaderAt/io.WriterAt (files, uploads), optional compression, copy-on-write clones / versions / dedup — separate module |
gosqlite.org/vfs/vault |
a SQLite database in a block-structured container where compression and encryption are independent options (plain, compressed, encrypted, or both): multi-recipient keyslots, crash-safe key rotation, tamper-evident storage (symmetric MAC or ed25519-signed root), optional rollback resistance via an external anchor, and offline Compact to reclaim space — live & queried in place, durable per transaction (vault.Open), or a snapshot (vault.OpenSnapshot); plus Pack / Unpack — separate module |
gosqlite.org/ext/<name> (+ /auto) |
opt-in loadable Go extensions — see the catalog |
Migrating
| Coming from | Change |
|---|---|
_ "github.com/mattn/go-sqlite3" |
→ _ "gosqlite.org"; sql.Open("sqlite3", ...) keeps working |
_ "modernc.org/sqlite" |
→ _ "gosqlite.org"; sql.Open("sqlite", ...) keeps working |
"github.com/glebarez/sqlite" / "gorm.io/driver/sqlite" |
→ "gosqlite.org/gorm"; sqlite.Open(dsn) keeps working |
ncruces/go-sqlite3 |
partial — database/sql + _pragma DSNs swap cleanly; custom UDFs/types need a rewrite |
Full per-package recipes, the _* DSN-flag table, and build-tag mapping: Migrating, DSN flags, Build tags. Runnable: examples/migrating/.
The drop-in claim is CI-enforced: every push runs gorm.io/gorm's full integration suite, plus vendored subsets of mattn/go-sqlite3's and modernc.org/sqlite's own test suites, against this module (with an xorm-compatibility lane alongside) — so compatibility is checked by tests upstream wrote, not by tests we wrote to flatter ourselves. Recipes and divergence tables: dev/upstream/.
Why CGo-free
Because SQLite is transpiled to Go (via modernc.org/sqlite) rather than C-bound, you get: builds in golang:alpine / distroless with no apk add; GOOS=… GOARCH=… go build cross-compilation that just works; clean go test -race; reproducible builds with no vendored amalgamation; and CI on providers that disallow CGo. The cost is a constant-factor gap on hot UDF/per-row paths — invisible for most applications. More in Getting started and Performance.
Examples
Runnable, smoke-tested programs under examples/, grouped by audience: migrating/ (drop-in recipes), getting-started/ (the modern on-ramp), features/ (one per capability — search, VFS, the ext/ catalog, hooks, sessions, …), plus standalone cross-module demos (liteorm/, encrypted-blobstore/, vault-blobstore/). just example <name> runs one; just examples smoke-tests all.
Development & contributing
just recipes drive everything: just (build + test + lint), just test, just test-race, just lint, just examples, just bench, just ci. The underlying commands are vanilla go test ./... etc. Architecture, invariants, conventions, and where-to-look live in AGENTS.md; maintainer reference (coverage matrices, upstream-suite recipes, perf baselines) in dev/.
Supported Go
The two most recent Go releases (the pin lives in go.mod). The typed APIs use modern idioms freely and gopls modernize is enforced in CI. See Supported Go.
Sponsors
This project is supported by:
- ssh2incus — an open-source SSH server that connects directly to Incus containers and virtual machines, routing incoming SSH connections to the right instance via the Incus API.
- mobydeck — a GitHub organization publishing open-source developer tools and infrastructure utilities across Go, C, TypeScript, shell, and Ruby.
If your company benefits from this driver and you'd like to be listed here, open an issue.
License
Apache 2.0. See LICENSE and NOTICE. This project incorporates work from modernc.org/sqlite (BSD-style; the Go wrapper layer is vendored with attribution), mattn/go-sqlite3 (MIT; a test subset is vendored to validate drop-in compatibility), glebarez/sqlite (MIT; the gorm/ sub-package), and ncruces/go-sqlite3 (MIT; several ext/ ports). Each is preserved under its original license — see the LICENSE.* files.
Acknowledgements
- modernc.org/sqlite — Jan Mercl's pure-Go SQLite transpilation, without which this library would not exist.
- mattn/go-sqlite3 — the C-based driver whose API we mirror.
- glebarez/sqlite — the gorm dialector our gorm sub-package is ported from.
- ncruces/go-sqlite3 — Nuno Cruces's CGo-free (WASM/wazero) driver, whose loadable-extension lineup several
ext/sub-packages are ported from. - asg017/sqlite-vec — the vector-search extension bundled by
modernc.org/sqlite/vecand re-exported here. - zalgonoise/fts — the typed FTS5 wrapper shape we expanded on.