{"id":49163,"date":"2025-09-05T13:03:18","date_gmt":"2025-09-05T17:03:18","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=49163"},"modified":"2025-09-08T14:28:43","modified_gmt":"2025-09-08T18:28:43","slug":"sqlite-on-macos-not-acid","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2025\/09\/05\/sqlite-on-macos-not-acid\/","title":{"rendered":"SQLite on macOS Not ACID"},"content":{"rendered":"<p><a href=\"https:\/\/bonsaidb.io\/blog\/acid-on-apple\/\">Jonathan Johnson<\/a> (2022):<\/p>\n<blockquote cite=\"https:\/\/bonsaidb.io\/blog\/acid-on-apple\/\"><p>From my investigation, Apple&rsquo;s version of SQLite instead replaces <code>PRAGMA fullfsync = on<\/code>&rsquo;s implementation to use <code>F_BARRIERFSYNC<\/code>.<\/p><p>SQLite users who are expecting <code>PRAGMA fullfsync<\/code> to provide durability\nguarantees in the event of power failures or kernel panics can <a href=\"https:\/\/twitter.com\/numist\/status\/1536859148897226753\">override xSync\nvia a custom VFS<\/a> or build SQLite from source.<\/p><p>[&#8230;]<\/p><p>Apple&rsquo;s documentation clearly states that for any guarantees about data loss due\nto power loss or kernel panic, you must use the <code>fcntl()<\/code> API with the\n<code>F_FULLFSYNC<\/code> command.<\/p><p>[&#8230;]<\/p><p>For most consumer applications, <code>F_BARRIERFSYNC<\/code> will be enough to provide\nreasonable durability with the benefit of performing much more quickly. However,\nthere are some situations where true ACID compliance is desired.<\/p><p>[&#8230;]<\/p><p>It&rsquo;s very confusing when a feature that&rsquo;s <a href=\"http:\/\/www3.sqlite.org\/pragma.html#pragma_fullfsync\">documented to be specific to\nmacOS<\/a> doesn&rsquo;t behave as documented on macOS.<\/p><\/blockquote>\n<p>Although, SQLite itself is open-source, as are <a href=\"https:\/\/opensource.apple.com\">many parts of macOS and iOS<\/a>, he says that the source for Apple&rsquo;s SQLite is not available.<\/p>\n\n<p><a href=\"https:\/\/www.agwa.name\/blog\/post\/sqlite_durability\">Andrew Ayer<\/a> (<a href=\"https:\/\/news.ycombinator.com\/item?id=45066999\">Hacker<\/a> <a href=\"https:\/\/news.ycombinator.com\/item?id=45005071\">News<\/a>):<\/p>\n<blockquote cite=\"https:\/\/www.agwa.name\/blog\/post\/sqlite_durability\"><p>Unfortunately, SQLite&rsquo;s documentation about its durability properties is far from clear. I cannot tell whether SQLite is durable by default, and if not, what are the minimal settings you need to use to ensure durability.<\/p><p>[&#8230;]<\/p><p>A Hacker News commenter who agrees with my reading of the documentation <a href=\"https:\/\/news.ycombinator.com\/item?id=45015366\">asked Hipp<\/a> how his comment is consistent with the documentation, but received no reply.<\/p><p>\nHipp also says that WAL mode used to be durable by default, but it was changed after people complained about poor performance.\nThis surprised me, since I had the impression that SQLite cared deeply about backwards compatibility, and weakening the\ndefault durability setting is a nasty breaking change for any application which needs durability.<\/p><p>[&#8230;]<\/p><p>My takeaway is that if you need durability, you&rsquo;d better set the <code>synchronous<\/code> option explicitly because who knows what the default is, or what it will be in the future.  With WAL mode, FULL seems to suffice.  As for DELETE mode, who knows if FULL is enough, so you&rsquo;d better go with EXTRA to be safe. And if your application might be used on macOS, enable <code>fullfsync<\/code>.\n<\/p><\/blockquote>\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/02\/17\/apple-ssd-benchmarks-and-f_fullsync\/\">Apple SSD Benchmarks and F_FULLSYNC<\/a><\/li>\n<\/ul>\n\n<p id=\"sqlite-on-macos-not-acid-update-2025-09-08\">Update (<a href=\"#sqlite-on-macos-not-acid-update-2025-09-08\">2025-09-08<\/a>): <a href=\"https:\/\/x.com\/SheriefFYI\/status\/1964768046675030076\">Sherief, FYI<\/a>:<\/p>\n<blockquote cite=\"https:\/\/x.com\/SheriefFYI\/status\/1964768046675030076\">\n<p>I was bitten by this in production! my advice would be to bundle your own SQLite and in general, bundle your own code as much as you can on macOS \/ iOS, never rely on OS claims of correctness.<\/p>\n<\/blockquote>\n<p>However, this is not possible if you&rsquo;re using SQLite through Core Data or SwiftData.<\/p>","protected":false},"excerpt":{"rendered":"<p>Jonathan Johnson (2022): From my investigation, Apple&rsquo;s version of SQLite instead replaces PRAGMA fullfsync = on&rsquo;s implementation to use F_BARRIERFSYNC.SQLite users who are expecting PRAGMA fullfsync to provide durability guarantees in the event of power failures or kernel panics can override xSync via a custom VFS or build SQLite from source.[&#8230;]Apple&rsquo;s documentation clearly states that [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2025-09-05T17:03:22Z","apple_news_api_id":"64dbc4f3-6627-417f-9943-e77970b4721a","apple_news_api_modified_at":"2025-09-08T18:28:46Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAQ==","apple_news_api_share_url":"https:\/\/apple.news\/AZNvE82YnQX-ZQ-d5cLRyGg","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[1321,143,164,31,2586,30,2077,2598,991,71,425,174],"class_list":["post-49163","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-data-integrity","tag-database","tag-documentation","tag-ios","tag-ios-18","tag-mac","tag-macos-12","tag-macos-15-sequoia","tag-open-source-software","tag-programming","tag-sqlite","tag-storage"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/49163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=49163"}],"version-history":[{"count":5,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/49163\/revisions"}],"predecessor-version":[{"id":49175,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/49163\/revisions\/49175"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=49163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=49163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=49163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}