{"slug": "sqlite-utils", "name": "sqlite-utils", "category": "databases", "category_name": "Databases", "description": "", "recommenders": 4, "commenters": 4, "warners": 0, "score": 3.457, "rising": -1.31, "first": "2026-01-24", "latest": "2026-07-05", "why": "\"make it easy to replcate\" Litestream and \"make it easy to use\" sqlite-utils, it just becomes easier.", "why_is_quote": true, "has_verdict": false, "sentiment": {"recommend": 4, "neutral": 0, "compare": 0, "warn": 0}, "spark": [0, 0, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0], "listed": true, "loved": [], "caveat": "", "short_quote": "\"make it easy to replcate\" Litestream and \"make it easy to use\" sqlite-utils, it just becomes easier.", "kind": "", "icon": true, "domain": null, "github_repo": "github.com/simonw/sqlite-utils", "official_url": "https://sqlite-utils.datasette.io", "pricing": "", "aliases": ["sqlite-utils"], "verdict": null, "praise": [{"label": "", "summary": "", "quotes": [{"id": 780681010, "item_id": 48792563, "url": "https://news.ycombinator.com/item?id=48792563", "by": "jph00", "date": "2026-07-05", "version": null, "stance": "recommend", "quote": "I'm a big fan of sqlite-utils", "excerpt": "I'm a big fan of sqlite-utils, but I really don't like how Python (particularly 3.12+) changes how sqlite's transactions work -- the native behavior explained in the sqlite docs is much better IMO. I understand why Python had to change it (to be compatible with other databases) but I don't think it's a good model for sqlite. Therefore, I created apsw-utils, a port of sqlite-utils to the amazingly-awesome apsw lib -- ", "context": "", "use_case": "SQLite utilities", "switched_from": "", "story": "sqlite-utils 4.0rc2, mostly written by Claude Fable (for about $149.25)"}, {"id": 753898704, "item_id": 47118669, "url": "https://news.ycombinator.com/item?id=47118669", "by": "westurner", "date": "2026-02-22", "version": null, "stance": "recommend", "quote": "sqlite-utils does SQLite FTS full text search config.", "excerpt": "Though the README is probably enough context, would there be value in an agent skill for this? https://agentskills.io/what-are-skills SKILL.md format: https://agentskills.io/specification#skill-md-format The skill creator skill SKILL.md: https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md . SWE bench involves solving GitHub issues. Which of the SWE bench agents read from or write to GitHub is", "context": "", "use_case": "SQLite full-text search setup", "switched_from": "", "story": "Show HN: Saga \u2013 A Jira-like project tracker MCP server for AI agents (SQLite)"}, {"id": 747958802, "item_id": 46747425, "url": "https://news.ycombinator.com/item?id=46747425", "by": "randito", "date": "2026-01-24", "version": null, "stance": "recommend", "quote": "\"make it easy to replcate\" Litestream and \"make it easy to use\" sqlite-utils, it just becomes easier.", "excerpt": "Great link. I've always been drawn to sqlite3 just from a simplicity and operational point of view. And with tools like \"make it easy to replcate\" Litestream and \"make it easy to use\" sqlite-utils, it just becomes easier. And one of the first patterns I wanted to use was this. Just a read-only event log that's replicated, that is very easy to understand and operate. Kafka is a beast to manage and run. We picked it at", "context": "", "use_case": "", "switched_from": "", "story": "Small Kafka: Tansu and SQLite on a free t3.micro"}]}], "caveats": [], "who": [], "tags": [], "use_cases": ["sqlite schema changes", "sqlite utilities", "sqlite full-text search setup", "sqlite cli tooling"], "compared": [{"slug": "llm", "name": "llm", "co": 3, "switched_from": 0, "switched_to": 0}, {"slug": "datasette", "name": "Datasette", "co": 3, "switched_from": 0, "switched_to": 0}, {"slug": "sqlite", "name": "SQLite", "co": 3, "switched_from": 0, "switched_to": 0}, {"slug": "apache-kafka", "name": "Apache Kafka", "co": 2, "switched_from": 0, "switched_to": 0}, {"slug": "litestream", "name": "Litestream", "co": 2, "switched_from": 0, "switched_to": 0}], "makers": [{"id": 786861409, "item_id": 49178838, "url": "https://news.ycombinator.com/item?id=49178838", "by": "simonw", "date": "2026-08-04", "version": null, "stance": "recommend", "quote": "but Datasette, sqlite-utils and LLM are not that.", "excerpt": "I'm planning an article at the moment in defense of lines of code. Saying \"lines of code are a bad measurement\" is too easy! It's about time someone presented an opposing argument. In my specific case, lines of code for my published open source projects is a metric that I trust, because I have high standards for those. I have plenty of other projects where I'll accept poor quality, unreviewed code (almost all of http", "context": "", "use_case": "", "switched_from": "", "story": "Eight Myths on Software Engineering and GenAI"}, {"id": 786846786, "item_id": 49177924, "url": "https://news.ycombinator.com/item?id=49177924", "by": "simonw", "date": "2026-08-04", "version": null, "stance": "neutral", "quote": "I have similar charts across my three main open source projects", "excerpt": "How's this? https://simonwillison.net/2026/Jul/13/datasette-code-frequency/ I have similar charts across my three main open source projects: https://github.com/simonw/datasette/graphs/code-frequency https://github.com/simonw/llm/graphs/code-frequency https://github.com/simonw/sqlite-utils/graphs/code-frequency", "context": "maintains datasette, llm and sqlite-utils", "use_case": "", "switched_from": "", "story": "Eight Myths on Software Engineering and GenAI"}, {"id": 785540112, "item_id": 49096257, "url": "https://news.ycombinator.com/item?id=49096257", "by": "simonw", "date": "2026-07-29", "version": null, "stance": "recommend", "quote": "My sqlite-utils CLI tool and Python library offers solutions to both the alter table limitations and the need for schema migrations.", "excerpt": "My sqlite-utils CLI tool and Python library offers solutions to both the alter table limitations and the need for schema migrations. For alter table it offers a \"transform\" command which implements the pattern of creating a new table with your desired scheme, copying data to it from the old table, then renaming the tables (all in a transaction): https://sqlite-utils.datasette.io/en/stable/cli.html#transforming-tables", "context": "", "use_case": "SQLite schema migrations", "switched_from": "", "story": "SQLite in Production: Optimizing WAL Mode, Concurrency, and VFS Layers"}, {"id": 782087360, "item_id": 48880460, "url": "https://news.ycombinator.com/item?id=48880460", "by": "simonw", "date": "2026-07-12", "version": null, "stance": "neutral", "quote": "I just added a new test explicitly covering this", "excerpt": "Thanks for the nudge, I just added a new test explicitly covering this: https://github.com/simonw/sqlite-utils/commit/d71420065903ff54247b5062b8c6af6165b7e638", "context": "", "use_case": "", "switched_from": "", "story": "Prefer Strict Tables in SQLite"}, {"id": 782032512, "item_id": 48877032, "url": "https://news.ycombinator.com/item?id=48877032", "by": "simonw", "date": "2026-07-11", "version": null, "stance": "recommend", "quote": "This inspired me to add a feature to my sqlite-utils Python library and CLI tool", "excerpt": "> Unfortunately, I don\u2019t think there\u2019s a way to ALTER a table to make it strict. I think you have to copy the data out of the non-strict table into the strict one. This inspired me to add a feature to my sqlite-utils Python library and CLI tool, so you can now use it to transform non-strict tables to strict (and vice-versa) like this: uvx sqlite-utils transform data.db mytable --strict Or in Python: import sqlite_uti", "context": "", "use_case": "", "switched_from": "", "story": "Prefer Strict Tables in SQLite"}, {"id": 781669344, "item_id": 48854334, "url": "https://news.ycombinator.com/item?id=48854334", "by": "simonw", "date": "2026-07-09", "version": null, "stance": "recommend", "quote": "The test coverage of sqlite-utils is solid", "excerpt": "The test coverage of sqlite-utils is solid - pytest-cov reports 95% total. The project has 9,973 lines of implementation code and 14,860 of test code. Here's the delete_where() test: https://github.com/simonw/sqlite-utils/blob/7a52214624ae0e2c3fdf07215c1bcfc1393dbd93/tests/test_delete.py#L20-L26 The problem with the test was that it asserted that the records were deleted inside of the same transaction as the delete, ", "context": "", "use_case": "SQLite CLI and library", "switched_from": "", "story": "sqlite-utils 4.0rc2, mostly written by Claude Fable (for about $149.25)"}], "threads": [{"url": "https://news.ycombinator.com/item?id=48873940", "title": "Prefer Strict Tables in SQLite", "mentions": 3}, {"url": "https://news.ycombinator.com/item?id=49176830", "title": "Eight Myths on Software Engineering and GenAI", "mentions": 2}, {"url": "https://news.ycombinator.com/item?id=48791708", "title": "sqlite-utils 4.0rc2, mostly written by Claude Fable (for about $149.25)", "mentions": 2}, {"url": "https://news.ycombinator.com/item?id=46690779", "title": "Small Kafka: Tansu and SQLite on a free t3.micro", "mentions": 2}, {"url": "https://news.ycombinator.com/item?id=49094346", "title": "SQLite in Production: Optimizing WAL Mode, Concurrency, and VFS Layers", "mentions": 1}, {"url": "https://news.ycombinator.com/item?id=48326802", "title": "SQLite is all you need for durable workflows", "mentions": 1}], "sentiment_by_month": {"2025-11": {}, "2025-12": {}, "2026-01": {"recommend": 2}, "2026-02": {"recommend": 1}, "2026-03": {}, "2026-04": {}, "2026-05": {}, "2026-06": {}, "2026-07": {"recommend": 1}, "2026-08": {}, "2026-09": {}, "2026-10": {}}, "versions": [], "version_unnamed": 0, "family_ref": null, "runs_on": null, "lines": [], "quotes": [{"id": 782085281, "item_id": 48880330, "url": "https://news.ycombinator.com/item?id=48880330", "by": "simonw", "date": "2026-07-12", "version": null, "stance": "neutral", "quote": "It uses \"PRAGMA foreign_keys=0\"", "excerpt": "It uses \"PRAGMA foreign_keys=0\" and \"PRAGMA defer_foreign_keys= ON\" before running the transformation, then resets those settings afterwards: https://github.com/simonw/sqlite-utils/blob/3f0471701b5f8c7de888a467020e5dd34310ce9a/sqlite_utils/db.py#L2571 That's the pattern recommended by SQLite here: https://www.sqlite.org/lang_altertable.html#otheralter", "context": "", "use_case": "SQLite schema changes", "switched_from": "", "story": "Prefer Strict Tables in SQLite"}, {"id": 780681010, "item_id": 48792563, "url": "https://news.ycombinator.com/item?id=48792563", "by": "jph00", "date": "2026-07-05", "version": null, "stance": "recommend", "quote": "I'm a big fan of sqlite-utils", "excerpt": "I'm a big fan of sqlite-utils, but I really don't like how Python (particularly 3.12+) changes how sqlite's transactions work -- the native behavior explained in the sqlite docs is much better IMO. I understand why Python had to change it (to be compatible with other databases) but I don't think it's a good model for sqlite. Therefore, I created apsw-utils, a port of sqlite-utils to the amazingly-awesome apsw lib -- ", "context": "", "use_case": "SQLite utilities", "switched_from": "", "story": "sqlite-utils 4.0rc2, mostly written by Claude Fable (for about $149.25)"}, {"id": 753898704, "item_id": 47118669, "url": "https://news.ycombinator.com/item?id=47118669", "by": "westurner", "date": "2026-02-22", "version": null, "stance": "recommend", "quote": "sqlite-utils does SQLite FTS full text search config.", "excerpt": "Though the README is probably enough context, would there be value in an agent skill for this? https://agentskills.io/what-are-skills SKILL.md format: https://agentskills.io/specification#skill-md-format The skill creator skill SKILL.md: https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md . SWE bench involves solving GitHub issues. Which of the SWE bench agents read from or write to GitHub is", "context": "", "use_case": "SQLite full-text search setup", "switched_from": "", "story": "Show HN: Saga \u2013 A Jira-like project tracker MCP server for AI agents (SQLite)"}, {"id": 748004306, "item_id": 46750269, "url": "https://news.ycombinator.com/item?id=46750269", "by": "tombert", "date": "2026-01-24", "version": null, "stance": "recommend", "quote": "", "excerpt": "I love the idea of SQLite, but I actually really dislike using it. I think part of my issue is that a lot of uses of it end up having a big global lock on the database file (see: older versions of Emby/Jellyfin) so you can't use it with multiple threads or processes, but I also haven't really ever find a case to use it over other options. I've never really felt the need to do anything like a JOIN or a UNION when doin", "context": "", "use_case": "SQLite CLI tooling", "switched_from": "", "story": "Small Kafka: Tansu and SQLite on a free t3.micro"}, {"id": 747958802, "item_id": 46747425, "url": "https://news.ycombinator.com/item?id=46747425", "by": "randito", "date": "2026-01-24", "version": null, "stance": "recommend", "quote": "\"make it easy to replcate\" Litestream and \"make it easy to use\" sqlite-utils, it just becomes easier.", "excerpt": "Great link. I've always been drawn to sqlite3 just from a simplicity and operational point of view. And with tools like \"make it easy to replcate\" Litestream and \"make it easy to use\" sqlite-utils, it just becomes easier. And one of the first patterns I wanted to use was this. Just a read-only event log that's replicated, that is very easy to understand and operate. Kafka is a beast to manage and run. We picked it at", "context": "", "use_case": "", "switched_from": "", "story": "Small Kafka: Tansu and SQLite on a free t3.micro"}]}