Today many web apps are built using React, Angular, Vue, Ember and others. These modern client-side rendered apps often make calls to Web APIs that are hosted on separate servers. This creates a problem: how do you configure your app to call the correct API URL in each environment?

For example, during development, you can host the API locally on localhost:3000. In production, the API can be hosted on another server at So you need your app to call localhost:3000 in development and in production. but how?

And the base URL is just one example of a setting that can change per environment. You can choose to change other settings per environment for performance, security, or logging purposes. Some of the approaches below apply for these common environment-specific configurations as well. But for the sake of simplicity, this post focuses on techniques for configuring URLs on a per environment basis.

Turns out, there are several ways to handle this. I found many insightful answers in the tweet thread. I’ve summarized eight options below. I have ordered these options (loosely) in the order that they should be considered. So, if you’re in a hurry, here are the top options to consider first. ,

Option 1: Host the API with the App
Easy. Simply host the app and the API from the same webserver, so relative URLs work everywhere. This avoids both the base URL issue as well as the cross-origin problems.

With this approach, you typically use a Continuous Integration (CI) server to create and deploy custom builds for each environment. It is a powerful, secure and versatile approach, but it requires each developer to create and maintain an .env file on their machine. Here’s a great post with some tricks to make this pretty painless.

You want to significantly change code deployed for production, such as removing code that is only used in non-production environments for performance or security reasons.

You are comfortable with the risk that comes with deploying different code to production than the code you run during development and QA.

Option 3: Runtime Configuration

With this approach, you configure your app for each environment by referencing the relevant configuration data at startup (as opposed to the builds discussed above). So unlike the above approach, with this approach the same code is deployed in all the environments. The configuration data you pass in at startup customizes the behavior of the app.

Of course, these approaches slightly alter your code at startup depending on the runtime configuration provided. But they differ from option #2 above, because the same code is deployed in all environments.

Option 4: Reverse Proxy

With this approach, you call the same relative URL in all environments. How does that work? Well, it is the responsibility of the front-end web server to forward the calls to the relevant APIs for each environment.

side note:
When we are talking about proxies, another proxy approach worth mentioning is proxy middleware (this is a completely different approach than the reverse proxy discussed above).

With proxy middleware running on your local machine, requests are forwarded to a specified URL during development. For example, if you are a React developer, create-react-app has proxy support built-in. It uses webpack’s proxy middleware.

Here’s a solid overview of the proxy approach using React and Express.

However: proxy middleware only solves the base URL issue in development. So to handle other environments like QA and production use one of the other techniques in this post.

Option 5: Docker

With Docker you can deploy the UI and API as separate containers, but create a “LAN” that allows the containers to communicate over the same network. Thus, the base URLs do not change in each environment. Containers run the same way in all environments. And you can pass the relevant environment variables to the containers in each environment. See Kubernetes or Docker Swarm for this approach.

Option 6: Sniffing the Environment

With this approach, you use code to “sniff”?? The current environment, usually by looking at the URL. For example, if the URL is http://localhost, you know you’re in development.

The advantage of this approach is simplicity. Developers don’t need to configure anything on their machine and you don’t need to monkey with CI server or web server configuration.

Leave a Reply

Your email address will not be published. Required fields are marked *