Setting serverless environments variables in a React app
A common question full-stack developers have is “How do I set the environment variables from my backend in my frontend app?”.
How do I set the environment variables from my backend in my frontend app?
For example, your React app might be calling an API endpoint in your backend. You ideally don’t want to hard code this in your frontend app. The main reason being, you might deploy your full-stack app to multiple environments and you’d like your React app to call the right API endpoint.
In this chapter, we’ll look at how to do this specifically between a React.js app and a serverless backend.
Here is a video of it in action.
Let’s look at the two parts of our workflow; developing and deploying.
While Developing
Here’s what we want to happening when developing locally:
- Start our local serverless development environment.
- It should output our backend environment variables (API endpoints, S3 buckets, Cognito authorizers, etc.).
- Then start our local React development environment.
- It should automatically pick up the backend environment variables.
As an example, let’s look at a really simple full-stack SST app. It has a simple Hello World API endpoint. And a React.js app.
import * as sst from "@serverless-stack/resources";
export default class MyStack extends sst.Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Create a HTTP API
const api = new Api(stack, "Api", {
routes: {
"GET /": "functions/lambda.handler",
},
});
// Create a React.js app
const site = new ReactStaticSite(this, "Site", {
path: "frontend",
environment: {
// Pass in the API endpoint to our app
REACT_APP_API_URL: api.url,
},
});
// Show the URLs in the output
stack.addOutputs({
SiteUrl: site.url,
ApiEndpoint: api.url,
});
}
}
Here we are using the ReactStaticSite
construct. It allows us to set React environment variables from our API.
environment: {
// Pass in the API endpoint to our app
REACT_APP_API_URL: api.url,
}
Now when we start our local development environment.
$ pnpm start
SST generates a file in the .build/
directory with the environment that we configured. It looks something like this.
[
{
"path": "frontend",
"stack": "dev-my-react-app-my-stack",
"environmentOutputs": {
"REACT_APP_API_URL": "https://fp21ziovfk.execute-api.us-east-1.amazonaws.com"
}
}
]
On the React side, we’ll now want to pick the environment variable up. To do this, we’ll use a really simple CLI (@serverless-stack/static-site-env
) that reads from this file and sets it as a build-time environment variable in React.
$ pnpm add --save-dev @serverless-stack/static-site-env
We can use the environment variable in our components using process.env.REACT_APP_API_URL
.
export default function App() {
const url = process.env.REACT_APP_API_URL;
return (
<div className="App">
Our API endpoint is: <a href={url}>{url}</a>
</div>
);
}
We can now wrap our start script with it.
"scripts": {
"start": "sst-env -- react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
So if we start our React local environment:
$ pnpm run start
It’ll contain the environment variable that we had previously set in our serverless app!
Next, let’s look at what happens when we deploy our full-stack app.
While Deploying
We need our React app to be deployed with our environment variables. SST uses CDK internally, so the flow looks something like this.
- Deploy our API.
- Build our React app.
- Replace the environment variables in our React app.
- Deploy our React app to S3 and CloudFront.
SST and the ReactStaticSite
construct do this automatically for you.
And that’s it! You now have a full-stack serverless app where the environment variables from your backend are automatically set in your React app. You don’t need to hard code them anymore and they work in your local development environment as well!
For further details, check out our example on building a React.js app with SST: How to create a React.js app with serverless.
For help and discussion
Comments on this chapter