By the end of this lesson, you will:
- Understand what an environment is and what types there are
- Dive into environment variables and what types of data can be stored in them
- Know how deploy your application to Heroku
What are environments?
Environments in software development refer to the place where your code runs. The “where” in this definition is less of a physical location, and refers more to a configured setup of tools, platforms, hardware and software. Each environment typically corresponds with a specific phase of the release process.
A Brief History
Stage 0: One Environment
In the beginning, we developed our applications directly in production. This was problematic for a number of reasons. Mainly, you had to deploy your code in order to see feedback. Think of how many times you write some functionality incorrectly. Every time you push broken code to production, it’s breaking the user experience for people who are currently on your application.
Stage 1: Two Environments
To alleviate this issue, we created development environments. Development environments are intended to:
- shorten the feedback loop (you can see if your code is working much more quickly without having to wait for a build or deployments)
- give us a low-risk place to write our code and try it out
Development environments typically live on your laptop and allow you to configure the application in a way that makes it easiest for you to actually develop. (e.g. you might use unminified versions of libraries and packages to make debugging easier)
While the development environment provided us with some answers to the problems with a single production environment, it also introduced some new ones:
- Just because it works on your machine, does not mean it will work on others (e.g. you might have a node module installed locally that is a lower version of one that gets installed in production if you haven’t locked down your package versions)
- Although rare, hardware can sometimes change how software behaves. So the system that is running your application might not be exactly the same as the one running it in production.
Stage 2: Three Environments
(Development, Staging, Production)
So, we created another environment that we call staging. This environment is meant to execute our code in an environment as close as possible to production, without actually disrupting production. The staging environment will often be accessible only internally so that employees and team members can do a round of quality assurance before deploying to production.
Stage 3: Four Environments
(Testing, Development, Staging, Production)
As we began to focus on automation, we developed more advanced test suites that would do their own round of quality assurance on our code before even showing it to team members. We’ve created testing environments to run our automated test suites that verify the integrity of our code.
Stage 4: Five Environments
(Testing, Development, CI, Staging, Production)
There is yet another environment that is common on modern development teams: Continuous Integration. It exists to run our tests, report back with success or failure, and in some cases, take additional action.
We all know to run our tests before we push, or after we merge, or before we deploy, but a continuous integration environment ensures that tests are run. We can’t forget. You can even add CI tools to your production deployment process, such that any commit that doesn’t pass its tests will be rejected.
So based on that history, we ended up with the modern environments we have today. The most common ones you’ll see are:
- the application is actively being developed
- should contain software that’s similar to that found in staging and production
- likely does not have similar hardware as staging and production
- the application is actively being tested, likely by an automated test suite
- uses pre-defined, rigid data for testing purposes
- the application is running a complete build to ensure everything is working as expected under a given setup
- should have the same software as your production environment
- is usually connected to your version control system
- often connected to staging and production for automatic deployments
- needs access to the exact data you’re using in your test environment
- a pre-release phase of the release process where internal team members may do a round of quality assurance
- should be hardware and software identical to production
- uses production-like data (often times you’ll grab a data dump from production to seed staging)
- has to consider privacy (is usually only intended to be accessible internally within the company or organization)
- the live, released version of the application
- defines the standard/expected hardware and software for the application
Environments can differ from each other in many ways. For example:
- You might want the mocked-out data in your test seeds to be more predictable/rigid than the data seeds you work with in development
- Your database connection strings will change between environments because you can’t and don’t want to use the same database in production that you’ll be using in development
- The configuration for automatic deployments will vary based on where your staging vs. production applications live
- The hostname for your different URLs will vary
- The port your application runs on might be 3000 in development, but 8080 in production depending on the tech stack and where it’s hosted.
- You likely want to use unminified versions of libraries and packages in development & testing for debugging purposes, but always want minified versions in production for performance reasons.
Environment Variables and Storing Sensitive Data
To handle these differences, we use environment configurations and variables. Environment variables represent values that differ between environments. They’re used across languages and platforms to set configuration options. They allow the same logic and code to interact with different sources. They are most often found in configuration files for server-side logic or build tools, and sometimes contain sensitive or private data such as API keys and database connections.
Because API keys and database connections can contain sesitive data, you don’t want to commit this to GitHub. Pushing up to GitHub can allow others to have access to your keys, allowing them to track your data or make API calls on your account. Instead of hardcoding their values into the codebase, we can store all of this sensitive information into environment variables in a
.env file that is gitignored.
The way you create environment variables can change depending on the framework you are using.
- React: You will need to create a
.envfile in the root of your project. Instructions are here.
- React Native: There are a couple of options you can use to create environment variables. The most reliable and commonly used one is react-native-config (over 85,000 downloads a week). However, if you run into issues, you can also try react-native-dotenv (only about 5,000 downloads a week).
- Svelte: You can bring in some smaller libraries including
@rollup/plugin-replace. You can find instructions here
- Vue: You can create environment variables following the docs here.
Getting Setup with Heroku
Although there are numerous ways of getting your application deployed to production including AWS & Netlify, Heroku is a commonly used platform for deployment that is reliable and can require much less setup than others. Please follow the instructions below to get setup on Heroku.
Step 1 - Install the Heroku CLI
We need to install the Heroku command-line tools to be able to run commands that communicate with our deployed application. Run this command to install the Heroku CLI:
brew tap heroku/brew && brew install heroku
Step 2 - Sign Up with Heroku
Create an account here. Once you have a username/password, you can login on your terminal:
$ heroku login
Step 3 - Create Heroku app
$ heroku create app_name
If you go back to Heroku in your browser, you should now see that you have an app listed under your personal apps that corresponds to the one you just created from the terminal. This command also added a new remote repository to our application. You can see all of your remote git details by running the following command:
$ git remote -v
Step 4 - Finish Deployment
Follow the following steps depending on what framework you are utilizing. For most FE technologies, the process of deployment is pretty straightforward. (BE can require a bit of additional work to run migrations and seed data) A common theme you will see when deploying to Heroku is that you will need to add a Procfile at the root of your folder.
A Procfile contains a number of process type declarations, each on a new line. Each process type is a declaration of a command that is executed when a dyno of that process type is started.
For example, if a web process type is declared, then when a dyno of this type is started, the command associated with the web process type, will be executed. This could mean starting a web server, for example (the default command that Heroku tries to run is
- React: If you built out an app using
create-react-app, the process of pushing it up to Heroku is very simple. Follow the instructions that Heroku has provided here.
- React-Native: It is not necessary to deploy your application to Google Play or Apple’s store as a result of $.
- Svelte: The docs in Svelte have a few ways of deploying your application. Experiment with running the build and pushing up to Heroku. If you run into issues, you can also try deploying with
- Vue: You can follow the official docs here in order to deploy your application to Heroku here.
You will inevitably have issues in production and can sometimes run into an unhelpful ‘Application Error’ when opening your app on Heroku. As a result, it’s definitely important to learn how to read the Heroku error logs. To read the Heroku logs, input the following commands below and address any errors that might be occuring.
//Gets you all the logs
$ heroku logs
//Gets you the latest log
$ heroku logs --tail
Heroku Environment Variables
In order to set your environment variables in production, you will need to navigate to your app here, and then click on
Settings. From there, click
Reveal Config Vars, where you can set your API keys and other variables along with their values.
Checks For Understanding
- What is an environment?
- What are the 5 different environments your code might run in and what are each of them used for?
- What kind of data might be stored in an environment variable?