Actually, Unix domain sockets are substantially more flexible than localhost. For exampe, Unix domain sockets have filesystem-based access controls, they can have meaningful paths instead of magic numbers, and they are trivially used across different containers (just bind mount the socket file in to whatever container, just like any other file).
This is dependent on the operating system. The Linux kernel obeys access permissions on the file inode, but Solaris doesn't. (I always forget how AIX, macOS, FreeBSD, NetBSD, and OpenBSD behave.) But even on Linux there's the classic race condition if your umask isn't set correctly when you invoke bind. Interestingly, on Linux you can fchmod the descriptor before calling bind, which is better than temporarily changing the umask around bind as it's not thread friendly--the umask is global so would effect whatever files are being opened in other threads at that moment.
But you don't need to rely on the permissions of the socket file inode itself. You can just create a directory with the restrictive permissions and then bind the socket into that directory. That's perfectly portable, presumably even to Windows, and also avoids umask races. In fact, using directories this way is almost always the superior option (e.g. for temporary files, etc), though it's a tad more leg work so unfortunately people rarely use that pattern.
But all Unix systems also support querying credentials over Unix domain sockets, where "credentials" basically means the UID and GID of the peer[1], which permits supporting user- or group-based authentication without passwords. I'm pretty sure Postgres supports this; that is, you can configure Postgres to allow user foo to access DB bar without a password, token, or signed cert. I submitted a patch many years ago so this would work on OpenBSD. (At the time OpenBSD provided getpeereid for querying peer credentials, but Postgres only supported SO_PEERCRED and some other mechanisms. Years later OpenBSD eventually adopted the SO_PEERCRED approach, which is what Linux uses, and made getpeereid a wrapper, because sometimes it's not worth swimming upstream. None of these are defined by POSIX but the capability is supported one way or another on all the extant Unix systems.)
[1] Depending on the OS, credentials can include other information, like PID.
I can see how it sometimes may make the application simpler and maybe, potentially, how you can have single proxy to serve multiple tenants (containers with applications) so that they maybe don't have to keep their own pools of connections.
The services would talk to each other locally and use the proxy to talk to the database using single connection pool.
But I don't see how this couldn't be as effective with TCP loopback (which actually is hacked to not invoke any TCP).
Granted, domain sockets are bit faster than localhost (https://redis.io/topics/benchmarks) but if this makes difference for your application you are likely using wrong architecture.
UDS can be permissioned using standard unix USER/GROUP which adds more flexible security structure (more so when you combine UDS with SE Linux).
This is opposed to localhost which is much harder to firewall from-localhost->to-localhost
The reason is that there is just too much surface between an application and the operating system to be able to guarantee safety.
And so we put applications into their separate VMs or containers and treat the entire container as part of the application. There are no other assets on that container.
Of course, if the container boundary isn't meaningful, you've complicated your system design for nothing.
And either way, TLS termination in a separate process is a potentially significant penalty to performance, as you'll have a lot more copies.
Low latency (e.g. HFT) = no database at all, esp. not on the fast paths. Mostly direct buffers for everything, including interprocess communication via file mapped memory.
That depends on your platform. FreeBSD actually runs localhost as tcp, and you can have delays, packet loss when the buffer is full, and congestion collapse on localhost. It's lots of fun, but if I asked for tcp and got tcp, I'm not terribly surprised. It's not like BSD hasn't had a better option for local sockets since forever (did unix domain sockets ship at the same time as tcp? I don't know, but they both shipped before I had a computer at home), so my fault for choosing poorly or using a language that doesn't support nice things.
You have two situations: 1. The application must/can run on the database server 2. The application must be able to run separately on dedicated app server (which is... almost every case).
If the application has to run on the database server, it can use localhost which is realistically as efficient as domain socket but is more flexible.
If the application has to run on another host, there is no problem, you can't use domain sockets anyway.