Use a backend proxy with app-level model aliases when one product needs OpenAI, Claude, and Gemini behind one API key; otherwise, keep a direct provider integration when provider-specific features are the point of the product. Short answer: centralize model selection, retries, token limits, and cost checks on the server, then let the client ask for a logical capability rather than a vendor identifier.

I design object-storage and data layers, so I don't start this decision with a demo prompt. I start with the invariants: credentials stay off the client, an alias resolves predictably, retries don't duplicate writes, and a budget rule is evaluated before traffic fans out. A unified runtime is useful because it turns a provider change into a backend policy change. It doesn't turn different models into the same system.

This is an architecture decision record for a Node.js-facing application, although the service example is Python because that is what I use to make HTTP behavior painfully explicit. The browser can still call a Node.js route that forwards to this service; the boundary matters more than the language. Keep the key server-side. Always.

What should a Node.js backend proxy do for OpenAI, Claude, Gemini, model mapping, and retries?