If your application is long lived you will get more benefit using the pooling functionality provided by the postgresql client libraries for your platform/language.
pgbouncer is an intimidatory, and thus another thing to break- it has it's own constraints (mainly things like prepared statements will block a connection/cannot be reused) and its application should be well understood.
For instance; I use it on a local socket on my zabbix master so that it can connect using a TLS encrypted pgsql socket. (something zabbix doesn't support). But for my main applications written in C++, I use connection pooling with nothing but the C++ client libraries.
If you're bringing up and tearing down connections very often, then you will get a lot of benefit from pgbouncer, but in my experience these cases are limited.
I would advocate for pgbouncer at the DB ingress level and your languages connection pooler at the application level.