60 comments

[ 2.1 ms ] story [ 82.7 ms ] thread
> json_extract returns native types. json_extract(data, '$.id') returns an integer if the value was stored as a number. Comparing it to a string silently fails. Always CAST(json_extract(...) AS TEXT) when you need string comparison.

More simply:

    sqlite> select typeof('{a:1}'->>'a') ;
    ╭──────────────────────╮
    │ typeof('{a:1}'->>... │
    ╞══════════════════════╡
    │ integer              │
    ╰──────────────────────╯
vs:

    sqlite> select typeof('{a:1}'->'a') ;
    ╭──────────────────────╮
    │ typeof('{a:1}'->'a') │
    ╞══════════════════════╡
    │ text                 │
    ╰──────────────────────╯
> The technical fix was embarrassingly simple: stop pushing to main every ten minutes.

Wait, you push straight to main?

> We added a rule — batch related changes, avoid rapid-fire pushes. It's in our CLAUDE.md (the governance file that all our AI agents follow):

> Avoid rapid-fire pushes to main — 11 pushes in 2h caused overlapping Kamal deploys with concurrent SQLite access.

Wait, you let _Claude_ push your e-commerce code straight to main which immediately results in a production deploy?

i hate to be so blunt but look around the site and then tell me you're surprised
Hey, Apple still takes their store down during product launches!
I'm fairly confident they let it write the blog post too.
This is the actual problem:

"Kamal runs blue-green deploys — it starts a new container, health-checks it, then stops the old one. During the switchover, both containers are running. Both mount ultrathink_storage. Both have the SQLite files open."

WAL mode requires shared access to System V IPC mapped memory. This is unlikely to work across containers.

In case anybody needs a refresher:

https://en.wikipedia.org/wiki/Shared_memory

https://en.wikipedia.org/wiki/CB_UNIX

https://www.ibm.com/docs/en/aix/7.1.0?topic=operations-syste...

> Wait, you let _Claude_ push your e-commerce code straight to main which immediately results in a production deploy?

Yikes. Thank you I'm not going to read “Lessons learned” by someone this careless.

I suspect they don't wear helmets or seatbelts either. Sigh. The "I'm so proud and ignorant of unnecessarily risky behaviors" meme is tiring.

The Meta dev model of diff reviews merge into main (rebase style) after automated tests run is pretty good.

Also, staging and canary, gradual, exponential prod deployment/rollback approaches help derisk change too.

Finally, have real, tested backups and restore processes (not replicated copies) and ability to rollback.

> Backups are cp production.sqlite3 backup.sqlite3

I use gobackup[0] as another container in compose.yml file which can backup to multiple locations.

[0]: https://gobackup.github.io/

Does cp actually work on live sqlite files? I wouldn’t expect it to, since cp does not create a crash-consistent snapshot.
Maybe if the system is idle
I've a busy app, i just deploy to canary. And use loadbalancer to move 5% traffic to it, i observe how it reacts and then rollout the canary changes to all.

how hard and complex is it to roll out postgres?

The fix appears to nicely asking the forgetful unreliable agent to please (very closely pretty please!) follow the deploy instructions (and also please never hallucinate or mess up, because statistics tells us an entity with no long term memory and no incentive to get everything right will do the job right 99.99999999% of the time, which is good enough to run an eshop) not deploy too often per hour.

With one simple instruction the system (99.9999% of the time) gains the handy property that “only” two processes end up with the database files open at once.

Thanks for the vibes!

I have to work with agents as a part of my job and the very first thing I did when writing MCP tools for my workflow was to ensure they were read only or had a deterministic, hardcoded stopgap that evaluates the output.

I do not understand the level of carelessness and lack of thinking displayed in the OP.

> embarrassingly simple

This is becoming the new overused LLM goto expression for describing basic concepts.

llm generated article.

please consider writing it yourself. quirks in human writing is infinitely more interesting than a next-token-predicted 500 word piece

But then how would they get people to buy their $99 AI CEO package?
Redis, four dbs, container orchestration for a site of this modest scope… generated blog posts.

Our AI future is a lot less grand than I expected.

How else will you get all those resume entries ! (/j)
Ironically, AI de-skilling results in a robust-sounding resume.
The LLM prose are grating read. I promise, you'd do a better job yourself.
Given how dumb their workflow is (let Claude Code push directly to production without supervision) I'm not so sure.
SQLite has a ".backup" command that you should always use to backup a SQLite DB. You're risking data loss/corruption using "cp" to backup your database as prescribed in the article.

https://sqlite.org/cli.html#special_commands_to_sqlite3_dot_...

Yeah, using cp to backup sqlite is a very bad idea. And yet, unless you know this, this is what Claude etc will implement for you. Every friggin' time.
Well, humans also default to 'cp' until they learn the better pattern or find out their backup is missing data.

Also, my n=1 is that I told Claude to create a `make backup` task and it used .backup.

I don't understand the double standard though. Why do we pretend us humans are immaculate in these AI convos? If you had the prescience to be the guy who looked up how to properly back up an sqlite db, you'd have the prescience to get Claude to read docs. It's the same corner cut.

There's this weird contradiction where we both expect and don't expect AI to do anything well. We expect it to yolo the correct solution without docs since that's what we tried to make it do. And if it makes the error a human would make without docs, of course it did, it's just AI. Or, it shouldn't have to read docs, it's AI.

It works fine as long as no one is writing to the sqlite file and you are not in WAL mode, which is not the default.
But we were talking server loads here: anyone runs sqlite server-side not in WAL mode?
The bottom part of the article mentions they use .backup - did they add that later or did you miss it?
"I know about the .backup command, there's no way I'm using cp to backup the SQLite db from production."

Oh.

Guess I know what I'm fixing before lunch. Thank you :)

Related, there is also sqlite3_rsync that lets you copy a live database to another (optionally) live database, where either can be on the network, accessed via ssh. A snapshot of the origin is used so writes can continue happening while the sqlite3_rsync is running. Only the differences are copied. The documentation is thorough:

https://sqlite.org/rsync.html

> Would We Choose SQLite Again? Yes. For a single-server deployment with moderate write volume, SQLite eliminates an entire category of infrastructure complexity. No connection pool tuning. No database server upgrades. No replication lag.

These are weird reasons. You can just install Postgres or MySQL locally too. Connection pool tuning certainly isn't anything you have to worry about for a moderate write volume. You don't ever need to upgrade the database if you don't want to, since you're not publicly exposing it. There's obviously no replication lag if you're not replicating, which you wouldn't be with a single server.

The reason you don't usually choose SQLite for the web is future-proofing. If you're totally sure you'll always stay single-server forever, then sure, go for it. But if there's even a tiny chance you'll ever need to expand to multiple web servers, then you'll wish you'd chosen a client-server database from the start. And again, you can run Postgres/MySQL locally, on even the tiniest cheapest VPS, basically just as easily as using SQLite.

Yeah, the cost - both operationally and coding-wise - of running pgsql in some cloud dwarfs the cost of lost orders. "We'll just deploy less often" is tribal knowledge that will absolutely be forgotten at some point and maybe there'll be more than two lost orders. Just setup postgresql.
I still haven't figured out a good way to due blue/green sqlite deploys on fly.io. Is this just a limitation of using sqlite or using Fly? I've been very happy with sqlite otherwise, rather unsure how to do a cutover to a new instance.

Anyone have some docs on how to cutover gracefully with sqlite on other providers?

I don't know if it's just me, but this whole post seems to have time traveled forward from about 3-4 days ago.

It's not just a repost. The thread includes a comment I made at the time which now from "1 hour ago".

Makes me wonder if it's an honest bug or someone has hacked the hacker news front page to sell their t-shits, mugs, and AI starter kits.

could have used firebird embedded, also a simple deployment such as sqllite, but better concurrency and more complete system, also a tad faster
If Nico send him an email. The AI CEO should take his offer.
NIH syndrome, almost mental health issues.
I took three weeks off from tech, read books from last century, and travelled Europe. Coming back, reading LLM generated content and code feels like nails on a chalkboard. Taste, it does not have taste.
Just use a 4gb server and install Postgres
> Yes. For a single-server deployment with moderate write volume, SQLite eliminates an entire category of infrastructure complexity. No connection pool tuning. No database server upgrades. No replication lag.

None of these is needed if you run sqlite sized workloads...

I like SQLite but right tools for right jobs... tho data loss is most likely code bug

(comment deleted)
I use SqLite for a small hobby project, fine for that. Wanted to read the article to see why I should not, but it attacked me with a "subscribe" popup, so I stopped there. The comments here seem to be based on daydreaming on scaling to a lot of users who need 24/7 uptime, which is not always the case.