That distinction is the whole thing, and everything else follows once you have it.
A mobile app has no environment at runtime. There is no shell, no process environment, nothing to read from. So anything your JavaScript reads as a configuration value has to be baked into the bundle at build time. It becomes a literal string in the shipped code.
Which means your local file works in development for a reason that does not generalise: the development server is running on your machine, in your shell, and substitutes the values as it bundles. On a build machine, that file does not exist, so the substitution produces undefined: which is exactly what you shipped.
So the answer to where they go: into the build configuration, per build profile, so the build service has them when it bundles.
The consequence people miss, and it matters more than the mechanics: a value baked into the bundle is readable by anyone with the app. Not obscured, not protected - present as a string in a file anyone can extract. So this mechanism is for configuration, never for secrets.
If something must stay secret, it belongs on a server you control, and the app calls that server. There is no arrangement in which a key in a mobile binary is private.