Securely Managing Database Credentials in Python with dotenv


Introduction
Before pushing your code to GitHub, you may want to hide some sensitive information from the public eye 👀.
Managing sensitive information in our Python projects is very important, especially when sharing code on GitHub.
Accidentally exposing credentials in your code can have serious consequences, including unauthorized access to your database, financial losses and even data breaches. For example, a developer might mistakenly push their credentials to a public repository, allowing malicious actors to exploit them.
In this article, we'll introduce the dotenv
module, which allows us to securely store sensitive credentials (like database usernames and passwords) in a .env
file. The dotenv
Python module helps us to load environment variables from a ‘.env’
file. The environment variables will serve as containers that will store the ‘sensitive credentials’ so we don’t put them directly in our code.
This means that the ‘.env’
file at no circumstance is supposed to make it to GitHub like the rest of our code.
In order to hide it, we will need a ‘.gitignore’
file.
In the ‘.gitignore’
file we will specify any file we want git to ignore when pushing our code to GitHub.
Prerequisites
Understanding of Python and SQLAlchemy
Installed SQLAlchemy and mysql-connector
Familiarity with environment variables and why they are important
A working MySQL database setup
Implementing dotenv for Secure Database Connections in Python
To get started, we will have to install the ‘dotenv’
module.
Installations
Windows (virtual environment)
When working on Windows, especially in a virtual environment, users might encounter file path or permission-related issues. Here's a reliable approach
- Install dependencies
# Install the dotenv module
pip install python3-dotenv
# We will later configure file path
Windows Subsystem for Linux ( WSL )
When using WSL, you might encounter compatibility issues with virtual environments. These problems often stem from the way WSL interacts with the Windows filesystem and handles paths.
To avoid these issues, it will be easier for us if we install dependencies globally in WSL instead of using a virtual environment
- Install dependencies
# Run code below directly on Ubuntu
sudo apt install python3-dotenv
Creating the .env and .gitignore
files
The next thing is to create two files, the ‘.env’
and ‘.gitignore
’ files
# Creting files
touch .env .gitignore
Adding environment variables
In the .env
file we just created, we are going to create environmental variables that we will store our credentials or sensitive data within. In our case, we want to hide our username, password and database name in our database connection string.
Add the following variables in the ‘.env’
file. Note that the variables are in all, capital letters and there is no space before or after the equal to sign.
# Environment Variable
DB_USERNAME='your-database-username'
DB_PASSWORD='your-database-password'
DB_NAME='the-name-of-the-database-in-use'
# Replace values with your credentials
Getting git to ignore the ‘.env’
file
After adding our environment variables, we need a way to tell git that, ‘Hey, this file should be ignored when pushing our code to GitHub”.
That is what the ‘.gitignore’
file is for. Its purpose is in the name of the file.
Now, in the ‘.gitignore’
file, we need to specify the file to ignore, which in our case is the ‘.env’
file.
# Specify the .env file by just typing the file name
.env
Importing the dotenv
module into our code
Say you have a file, ‘config.py’
which contains your database configuration code, where the connection string exists. Import the dotenv
module into that file. Now we only need a section of the entire module called ‘load_dotenv’
. After importing it, we need to initialize it as well.
# import the module
from dotenv import load_dotenv
# Initialize the load_dotenv
load_dotenv()
For Windows users, you’ll need to ensure correct file path resolution for the ‘.env’ file due to file path or permission-related issues.
- Configure
‘.env’
usingPath
# Import Path for path handling
from pathlib import Path
from dotenv import load_dotenv
# Resolve BASE_DIR
BASE_DIR = Path(__file__).resolve().parent
# Load .env file explicitly
load_dotenv(Path(BASE_DIR, '.env'))
Importing ‘os’
We need to import ‘os’
which will give the dotenv
module access to our operating system. It is on our operating system that we have the ‘.env’
file saved. We need to be able to access it so we can load the environment variables into our ‘config.py’
file.
# import os
import os
Accessing the environmental variables
Now that we have imported the load_dotenv
module and os
, we can go on to load the environment variables into the ‘config.py‘
file.
You may go on to print them to the terminal to be sure they have been loaded and can be accessed from the ‘config.py’
file.
# Access the environment variables
database_username = os.getenv("DB_USERNAME")
database_password = os.getenv("DB_PASSWORD")
database_name = os.getenv('DB_NAME')
# print env variables for testing reasons
print(database_username, database_password, database_name)
Replacing the credential with the variables
Next, we replace all that sensitive data with their corresponding variables in our connection string.
We use the f-string to format the string and pass the variable in curly braces{} into the string.
# Replace values in connection string
connection_str = f'mysql+mysqlconnector://{database_username}:{database_password}@localhost/{database_name}'
Final config.py
file
When you are done replacing the values with the variables, your final config.py file should look something like this:
- For Windows Users
# Import Path for path handling
from pathlib import Path
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from dotenv import load_dotenv
import os
# Resolve BASE_DIR
BASE_DIR = Path(__file__).resolve().parent
# Load environment variables from the .env file explicitly
load_dotenv(Path(BASE_DIR, '.env'))
# Access the environment variables
database_username = os.getenv("DB_USERNAME")
database_password = os.getenv("DB_PASSWORD")
database_name = os.getenv('DB_NAME')
#print(database_username, database_password, database_name)
connection_str = f'mysql+mysqlconnector://{database_username}:{database_password}@localhost/{database_name}'
engine = create_engine(connection_str)
try:
#establishes an active connection to our dtabase
connection = engine.connect()
print('Located and connected to database')
# Closing the open connection
connection.close()
except Exception as e:
print(f'An error occured: {e}')
DBSession = sessionmaker(bind = engine)
session = DBSession()
- For WSL/ Linux Users
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from dotenv import load_dotenv
import os
# Load environment variables from the .env file
load_dotenv()
# Access the environment variables
database_username = os.getenv("DB_USERNAME")
database_password = os.getenv("DB_PASSWORD")
database_name = os.getenv('DB_NAME')
#print(database_username, database_password, database_name)
connection_str = f'mysql+mysqlconnector://{database_username}:{database_password}@localhost/{database_name}'
engine = create_engine(connection_str)
try:
#establishes an active connection to our dtabase
connection = engine.connect()
print('Located and connected to database')
# Closing the open connection
connection.close()
except Exception as e:
print(f'An error occured: {e}')
DBSession = sessionmaker(bind = engine)
session = DBSession()
Conclusion
Managing sensitive information in our Python projects is very important, especially when sharing code on GitHub. This article introduces the dotenv
module, which allows us to securely store sensitive credentials (like database usernames and passwords) in a .env
file. These credentials are then accessed through environment variables instead of being hardcoded into our scripts.
The steps covered include:
Installing the
dotenv
module.Creating a
.env
file to store sensitive information and a.gitignore
file to ensure the.env
file is not pushed to GitHub.Loading and accessing the environment variables using the
dotenv
andos
modules.Replacing sensitive information in our database connection string with these variables.
By following this guide, we can ensure our credentials remain secure while keeping our codebase clean and professional.
Subscribe to my newsletter
Read articles from Rhoda Oduro-Nyarko directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Rhoda Oduro-Nyarko
Rhoda Oduro-Nyarko
The more I learn the more I realize how much I don't know!