Other databases cache plans and have for years because it's very useful, many (most?) apps run many of the same statement with differing parameters, its a big win. They do this without the client having to figure out the statement matching logic like your various PG Orms and connection poolers try and do.
They also do things like auto parameterization if the statement doesn't have them and parameter sniffing to make multiple different plans based on different
values where it makes sense.
https://learn.microsoft.com/en-us/sql/relational-databases/q...
You can also get this, add HINTs to control this behavior if you don't like it or its causing a problem in production, crazy I know.
https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-tr...
PG is extremely primitive compared to these other systems in this area, and it has to be since it doesn't cache anything unless specifically instructed to for a single connection.