DEV Community

Cover image for Using .env Files for Environment Variables in Python Applications
Jake Witcher
Jake Witcher

Posted on

Using .env Files for Environment Variables in Python Applications

Applications are made to be deployed. At some point during development you will need to think about the environment in which your application will run and the potentially sensitive or environment specific information your application will need to perform its tasks.

Environment variables are one of the key ways software developers provide an application with this kind of information, however running and testing an application locally that is dependent on environment variables can be a hassle if you are setting those variables on your local machine's environment.

The process of setting or changing an environment variable is time consuming and over time the number of environment variables you have to manage grows out of control. Eventually naming conflicts becomes an issue and every new variable requires a lengthy prefix to distinguish itself from similar variables.

Using a .env file will enable you to use environment variables for local development without polluting the global environment namespace. It will also keep your environment variable names and values isolated to the same project that utilizes them.

A .env file is a text file containing key value pairs of all the environment variables required by your application. This file is included with your project locally but not saved to source control so that you aren't putting potentially sensitive information at risk.

# environment variables defined inside a .env file
GCP_PROJECT_ID=my-project-id
SERVICE_ACCOUNT_FILE=path/to/serviceAccountCredentials
STORAGE_BUCKET_NAME=my-super-important-data
Enter fullscreen mode Exit fullscreen mode

Nearly every programming language has a package or library that can be used to read environment variables from the .env file instead of from your local environment. For Python, that library is python-dotenv. Once the library is installed, an average use case for python-dotenv only requires adding two lines of code to your project.

from dotenv import load_dotenv

load_dotenv()
Enter fullscreen mode Exit fullscreen mode

load_dotenv() will first look for a .env file and if it finds one, it will load the environment variables from the file and make them accessible to your project like any other environment variable would be.

import os
from dotenv import load_dotenv

load_dotenv()

GCP_PROJECT_ID = os.getenv('GCP_PROJECT_ID')
SERVICE_ACCOUNT_FILE = os.getenv('SERVICE_ACCOUNT_FILE')
STORAGE_BUCKET_NAME = os.getenv('STORAGE_BUCKET_NAME')
Enter fullscreen mode Exit fullscreen mode

If an environment variable is not found in the .env file, load_dotenv will then search for a variable by the given name in the host environment. This means that when your project is running locally and the .env file is present, the variables defined in the file will be used. When your project is deployed to a host environment like a virtual machine or Docker container where the .env file is not present, the environment variables defined in the host environment will be used instead.

By default load_dotenv will look for the .env file in the current working directory or any parent directories however you can also specify the path if your particular use case requires it be stored elsewhere.

from dotenv import load_dotenv
from pathlib import Path

dotenv_path = Path('path/to/.env')
load_dotenv(dotenv_path=dotenv_path)
Enter fullscreen mode Exit fullscreen mode

For most applications, that's all the information you should need to be productive with python-dotenv however there are a few additional features which you can read about in the python-dotenv documentation.

One of the benefits of using a .env file is that it becomes much easier to develop with environment variables in mind early on. Thinking about these things at an earlier stage of the development process will make it easier for you to get your application ready for deployment.

If you are deploying your application in a Docker container, you can seamlessly transition to running and testing your application in a locally run container by using the flag --env-file .env with your docker run command. Docker will then set the same environment variables you've been using through python-dotenv in the container's environment.

Without a .env file, environment variables are a cumbersome albeit necessary part of testing your application locally. By using a .env file and the python-dotenv library, working with environment variables becomes much more manageable and will get you developing with deployment in mind right from the start.

Top comments (16)

Collapse
 
navporky profile image
NK • Edited

Hi Jake,

I am a noob, trying to learn python along with good practices. Now the queries: The official python-dotenv documentation talks about using the dotenv alongside settings module (python-settings). The load_dotenv() function is also recommended to be put in settings.py. Unable to wrap my head around the following:

  1. Though you have not advised it, why is it advised by many to use both? wouldn't load_dotenv work in any .py file?
  2. While going to pipenv shell for the project, the .env file is automatically loaded. What loads the settings.py file (which has code to load dotenv)?
  3. if .env is excluded from git via .gitignore then, is the other team developer/ tester support to make his own while looking at settings.py for what all values could have been there? and only after the error of not finding the .env file is encountered/ reading the readme.md file?
  4. In production, the environment variables are recommended to set at OS level? Why not in the same .env file, which can be manually created?
  5. For any environment - dev/ test/ production, the code could be written to produce a template .env file with just keys (Key=) and user (dev/ tester, prod) team member can just fill the value in before using. Is this not workable and logical way to do this?
  6. Just looked at python-decouple (as an alternate to python-settings) , won't this is even better as it can handle datatypes as well?

Thanks.

Collapse
 
hirushaadi profile image
Hirusha Adikari
  1. i think load_dotenv() would be enough (it always works on linux, where you would normally deploy a web app)
  2. you will have to import it manually and use. for testing of that file by running it directly, you can put it under if name == "main"
  3. you can add it to the docs of the program and keep a .env.example file filled with dummy values or no values at all (with just the structure)
  4. its secure to keep it away from application's code and config files. doing this, you can ensure that the data is only accessible to the application and not to other users or processes on the same machine
  5. haven't tried it
Collapse
 
ilija profile image
ilija

Tnx for article! But there is one important caveat here: if you use Linux for example you can not use env names like HOME or NAME or LOGNAME. Because your app variables from .env file (in currently working directory) will be overwritten by the global (from Linux).

For example: in case you put in .env NAME=Michale and you are logged in as user Daniel, inside your python script os.getenv("NAME") will return Daniel instead of Michael. And most probably this is not something you want in your app....

I guess there is different ways to resolve this, but most obvious one for me is to avoid this names entirely and to use some convention like APP_NAME or APP_HOME_DIR....

Collapse
 
kmistele profile image
Kyle Mistele

This is a great way to store API keys or other secrets so that they’re not hard coded into your application!

Collapse
 
jakewitcher profile image
Jake Witcher

Absolutely! Thanks for pointing that out. A .env file is a great way to work on a project with those kinds of security concerns in mind without the overhead of storing that information as a system environment variable on your computer.

Collapse
 
10codedev profile image
10CodeDev

Really nice writeup! I was just playing around with Python-DotEnv today.

Collapse
 
jakewitcher profile image
Jake Witcher

Thanks! While it is a very lightweight package, there’s more to it than I initially realized. I’ve primarily used it as described in the article but it does have features that allow for a few other use cases.

Collapse
 
mrhili profile image
Mrhili Mohamed Amine

no pip install needed ?

Collapse
 
mrhili profile image
Mrhili Mohamed Amine

pip install python-dotenv

Collapse
 
lico profile image
SeongKuk Han

Thank you so much!

Collapse
 
pradeepb28_ profile image
deepu

my python script and .env file are in the same folder but somehow it is unable to read the file unless I specify the path.

Collapse
 
cincybc profile image
CincyBC

If you use an Anaconda environment, you can set environment variables in the Conda environment without needing .env files!

Collapse
 
tazim404 profile image
Tazim Rahbar

Is there any way to add new environment variable into .env file from python code.

Collapse
 
thierrynjike profile image
Thierry Njike • Edited

you can write inside using this

with open("$path/to/.env", 'a+') as newenv:
    newenv.write("\n$varname=$varvalue")
load_dotenv()           #load vars again to consider the new added one

Enter fullscreen mode Exit fullscreen mode
Collapse
 
shijoshaji profile image
Shijo Shaji

Thanks, had a chance to try this today

Collapse
 
brunofariasdo profile image
Bruno de Oliveira

It helped me a lot, thank you!