HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
ncruces
go-sqlite3
Go2023–2026
ncruces / go-sqlite3

go-sqlite3

Go bindings to SQLite using wasm2go

11Distinct people
84Mentions
0Explicit recommenders
1.1KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Go bindings to SQLite using wasm2go

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 8–Nov 15 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/15/2026, 2:04:58 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year84 dated mentions

Observed mentions: 2023-04-08 05:04:20 UTC to 2026-10-21 22:17:16 UTC.

01020302023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 21 mentions; 2 submissions, 19 comments20232024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 13 mentions; 1 submissions, 12 comments20242025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 35 mentions; 3 submissions, 32 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 15 mentions; 0 submissions, 15 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC21219
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC13112
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC35332
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC15015

What Hacker News says

21 sources
Recent SQLite builds include the memdb [1] VFS (and the associated sqlite3_serialize and sqlite3_deserialize APIs) by default. How does this compare? I'm also curious what use cases you had in mind. My SQLite wrapper reimplements the memdb [2] VFS mostly as an exercise of the VFS API, but it provides a few additional niceties. The backing memory doesn't need to be contiguous, nor is it copied when the DB grows/shrinks. This makes it possible to have significantly larger in memory DBs. I also make it easy to bootstrap the database from (e.g.) a file on disk, or data embed in the binary. It's not as easy, however, to access the DB bytes after the DB goes “live.” [1] https://www3.sqlite.org/src/file?name=src/memdb.c [2] https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb#s...
In Show HN: sqlite-memory-vfs - Open a SQLite db in Python without hitting disk
database/sql adds some overhead; in return, it gives you a connection pool, and tries not to have you worry about connections. A lot of the interesting features of SQLite are connection oriented, and compared to other databases, connections are cheap (because it's all local). So the things database/sql offers are (relatively) less valuable, and it makes other things harder. Yet (IMO) connection pools still offer some performance benefits, not having to worry about (re)preparing statements on new connections is still helpful, and many of the connection oriented things you might want to do can be exposed through database/sql with some imagination. I have a lot of respect for crawshaw and zombiezen; I started from their PoV. But I've since come around to database/sql. A lot of what is mentioned in [1] has been fixed in database/sql or can be
Read the rest
fixed in drivers: parameter names now work in database/sql; their approach to statement caching isn't necessarily better, but can be added to a driver, or live in a compatible framework; panics vs. errors is contentious; savepoints can be made to work just fine [2]; and for contexts, I started with crawshaw and built an improved version of it into my driver, that is both low overhead, interacts well with the Go scheduler, and doesn't start additional goroutines. Living in database/sql land gives you access to other amazing tooling like SQLC, just to name a single one. And it doesn't need to be either/or: drivers should support both high and low level APIs. [1]: https://crawshaw.io/blog/go-and-sqlite [2]: https://pkg.go.dev/github.com/ncruces/go-sqlite3/driver#exam...
In Show HN: My Go SQLite driver did poorly on a benchmark, so I fixed it
One problem with WASM is that, at this point (2023), the only easy way of building that, is to statically link everything C into one WASM blob (so you can't use my blob). But you can try to use my build scripts, and tweak my code, to build SQLite+sqlite-vss+Faiss into one large WASM. If you use my patches/imports/exports/config for SQLite, my binding will gladly take your WASM blob, without modification to the Go code. All you need to do is set this global variable (and not import package embed, which embeds my WASM and sets this variable for you at init): https://pkg.go.dev/github.com/ncruces/go-sqlite3#pkg-variabl... Ping me on GitHub if you need help. Vector search is on my meters long todo list, but I'd rather do it in Go if at all possible.
In Show HN: My Go SQLite driver did poorly on a benchmark, so I fixed it
The major one is (cross) compilation and portability. You can (e.g.) easily whip up a small CLI that embeds an SQLite database in the binary [1], cross compile this to all the platforms Go supports [2], copy one file, and be reasonably sure it'll run in any of them. This is an example of embedding a database in a binary (with go:embed), and opening it for reading/writing in memory. You can then save the modified copy to disk using the backup API: [1]: https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb#e... [2]: https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b...
In Show HN: My Go SQLite driver did poorly on a benchmark, so I fixed it
The nitty gritty is in another answer. The commits implementing the new function cache are these two: https://github.com/ncruces/go-sqlite3/compare/0b093b7c...986... Creating good, representative, benchmarks is hard. I use speedtest1 [1] but this tests WASM/SQLite and my VFSes, not the Go driver that wraps it. I already forked this benchmark and will run it regularly, but I may also adapt it into a Go benchmark (easier to run, benchstat compatible, etc). [1] https://sqlite.org/src/file/test/speedtest1.c
In Show HN: My Go SQLite driver did poorly on a benchmark, so I fixed it
ncruces·Dec 15, 2023Submission

Show HN: My Go SQLite driver did poorly on a benchmark, so I fixed it

https://github.com/ncruces/go-sqlite3 was doing poorly on this benchmark that was posted yesterday to HackerNews [1]. With the help of some pprof, I was able to trace it to a serious performance regression introduced two weeks ago, and come up with the fix (happy to field questions, if you're interested in the nitty gritty). It's not the fastest driver around, but it's no longer the slowest: comfortably middle of the pack. It's based on a WASM build of SQLite, and thanks to https://wazero.io doesn't need CGO. [1]: https://news.ycombinator.com/item?id=38626698
234 points · Open discussion
OK, so if I'm looking at this right, a smarter, wider cache goes a great length to fixing the issue. In [1] I implemented a simple PLRU bit cache, and I'm seeing an 8x performance improvement in some of the tests I was doing worse in: Before: bench-ncruces - simple insert query dbsize bench-ncruces - simple 21224 16495 58687488 bench-ncruces - complex/200/100/20 insert query dbsize bench-ncruces - complex/200/100/20 14993 15228 25354240 bench-ncruces - many/N=10 query dbsize bench-ncruces - many/N=10 483 36864 bench-ncruces - many/N=100 query dbsize bench-ncruces - many/N=100 3129 36864 bench-ncr
Read the rest
uces - many/N=1000 query dbsize bench-ncruces - many/N=1000 28034 94208 bench-ncruces - large/N=50000 query dbsize bench-ncruces - large/N=50000 428 501981184 bench-ncruces - large/N=100000 query dbsize bench-ncruces - large/N=100000 779 1003761664 bench-ncruces - large/N=200000 query dbsize bench-ncruces - large/N=200000 1475 2007330816 bench-ncruces - concurrent/N=2 query dbsize bench-ncruces - concurrent/N=2 13091 56573952 bench-ncruces - concurrent/N=4 query dbsize bench-ncruces - concurrent/N=4 14731 56573952 bench-ncruces - concurrent/N=8 query dbsize bench-ncruces - concurrent/N=8 24730 56573952 After: bench-ncruces - simple insert query dbsize bench-ncruces - simple 5128 3026 58687488 bench-ncruces - complex/200/100/20 insert query dbsize bench-ncruces - complex/200/100/20 3127 3730 25354240 bench-ncruces - many/N=10 query dbsize bench-ncruces - many/N=10 93 36864 bench-ncruces - many/N=100 query dbsize bench-ncruces - many/N=100 403 36864 bench-ncruces - many/N=1000 query dbsize bench-ncruces - many/N=1000 3470 94208 bench-ncruces - large/N=50000 query dbsize bench-ncruces - large/N=50000 444 501981184 bench-ncruces - large/N=100000 query dbsize bench-ncruces - large/N=100000 717 1003761664 bench-ncruces - large/N=200000 query dbsize bench-ncruces - large/N=200000 1401 2007330816 bench-ncruces - concurrent/N=2 query dbsize bench-ncruces - concurrent/N=2 3275 56573952 bench-ncruces - concurrent/N=4 query dbsize bench-ncruces - concurrent/N=4 3404 56573952 bench-ncruces - concurrent/N=8 query dbsize bench-ncruces - concurrent/N=8 4918 56573952 There's still work to do. I could use ints rather than strings for function identifiers. I'll evaluate that later. [1]: https://github.com/ncruces/go-sqlite3/commit/964a42c76deb9c7...
In I benchmarked six Go SQLite drivers
The performance difference was larger than I had expected. But this is good. To fix a recent crash [1] that was happening due to a particular case of reentrancy, which only showed up when I implemented virtual tables and queried other tables to implement one (e.g.: Go calls sqlite3_step to execute a query, which calls Go because it's a query on virtual table, which calls sqlite3_step to scan another table) I introduced a performance regression. The fix [2] was not to reuse some objects I was allocating once per connection. A mitigation for the regression was (very naive) caching [3]. TLDR: my caching is just not good enough. Simply caching more will go a long way (confirmed already by doubling cache size), but now that I have a good benchmark, I'll do better. I expect to cut numbers for CPU bound tests in half due to this mishap. So, than
Read the rest
In I benchmarked six Go SQLite drivers
For the WASM one (disclaimer: I built it) it's at least reasonably simple to reproduce the build [1], and the resulting blob is fully cross platform. Also, although I do (lightly) patch SQLite which might invalidate results in your view, the SQLite team is producing/testing/releasing WASM builds of SQLite built with much the same toolchain, which, hopefully, smokes out compiler bugs. [1]: https://github.com/ncruces/go-sqlite3/blob/main/.github/work...
In I benchmarked six Go SQLite drivers
I'm the author or the WASM (+wazero) based github.com/ncruces/go-sqlite3. Happy to field questions. W.r.t. benchmark results. wazero's current compiler is somewhat naive, which may explain a large performance delta in CPU bound tests. A new compiler is in the works [1]. OTOH it seems interesting that in the (IO bound?) large test I'm doing better than modernc. I wonder why. I'll dig deeper into the results. [1]: https://github.com/tetratelabs/wazero/pull/1869
In I benchmarked six Go SQLite drivers
Disclosure: I'm working on alternative Cgo-less bindings for SQLite, using wazero. https://github.com/ncruces/go-sqlite3 One of the problems of the modernc approach (IMO) is that they're not just transpiling CPU/compute stuff, but entirely OS/platform stuff. Each Go file of theirs is a xxx_os_arch.go that starts with 100s of OS-#defines-as-consts, and goes on to transpile fully #ifdefed code. It also implements antithetical (in Go) stuff like goroutine local storage, because libc pthreads can't live without it. And all IO is via direct syscalls that will never play nice with the Go scheduler, because again, this is OS level stuff. WASM defines a cross platform CPU and an ABI, and using that for compute and the bottom OS layer in Go you get (IMO) a nicer end result. Given the hard task of generating decent code from WASM at load time (waze
Read the rest
ro's compiler is pretty naive, a better one is being developed, but it will take seconds to generate good code for anything non trivial like SQLite) I wouldn't mind having a solution that translated to Go, or Go ASM, at build time.
In Show HN: Gogosseract, a Go Lib for CGo-Free Tesseract OCR via Wazero

Showing the 15 most recent of 21 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.