When proxy_pass http://api.internal; names a host directly, nginx resolves it at configuration load time and caches the address for the lifetime of the worker. If the upstream's address changes, for example a container rescheduled onto a new IP or a DNS record updated during a deploy, nginx keeps sending traffic to the old address until it is reloaded.
Using a variable forces runtime resolution: set $upstream api.internal; proxy_pass http://$upstream;. That form requires a resolver directive naming a DNS server, otherwise nginx fails to start with no resolver defined to resolve api.internal.
The variable form has two side effects. It disables the URI-replacement behavior of proxy_pass, so the path must be appended explicitly, and it means a DNS failure produces a 502 at request time rather than a startup error. Set resolver 127.0.0.11 valid=10s; inside a container using Docker's embedded DNS, adjusting valid to control how long nginx caches an answer independently of the record's own TTL. nginx Plus offers a resolve parameter on upstream servers; the open source build does not.