Postgres runs your query fast exactly five times. Then it changes its mind.
Slow in the app, fast in psql, and both of them are right
A prepared statement ran in 274 ms for five executions and 2,319 ms from the sixth, on the same connection in the same minute. One EXPLAIN ANALYZE is a sample of size one and cannot see this; twelve in a row, with the plan kept per run, can. The plan cache mechanism behind it, why psql cannot reproduce it, which drivers trigger it, and the one-line fix. Measured on PostgreSQL 17 using ExoBench with twelve repetitions per connection.