Configuration and SECRET_KEY

Introduction

Flask stores settings in app.config—a dict-like object for debug flags, database URLs, and secrets. This chapter uses config classes, .env files with python-dotenv, the instance/ folder, and explains why SECRET_KEY must be random and private in production.

Prerequisites

app.config Basics

python
from flask import Flask
 
app = Flask(__name__)
app.config["DEBUG"] = True
app.config["SECRET_KEY"] = "dev-only-change-me"
app.config["ITEMS_PER_PAGE"] = 20

Access in views:

python
@app.route("/")
def index():
    limit = app.config["ITEMS_PER_PAGE"]
    return f"Showing {limit} items"

Common keys:

KeyPurpose
DEBUGDev traceback and reload
SECRET_KEYSigns sessions and CSRF tokens
TESTINGTest mode behavior
SQLALCHEMY_DATABASE_URIDB URL (Flask-SQLAlchemy, later)

Config Classes

Apply when creating app:

python
from flask import Flask
 
def create_app(config_name="development"):
    app = Flask(__name__)
    config_map = {
        "development": DevelopmentConfig,
        "production": ProductionConfig,
        "testing": TestingConfig,
    }
    app.config.from_object(config_map[config_name])
    return app

Code explanation:

  • from_object loads uppercase attributes from the class onto app.config

Load From .env

Create .env (gitignored):

env
FLASK_DEBUG=1
SECRET_KEY=your-long-random-string-here
DATABASE_URL=mysql+pymysql://user:pass@localhost/mydb

Load in app.py or factory:

python
import os
from dotenv import load_dotenv
from flask import Flask
 
load_dotenv()
 
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
app.config["DEBUG"] = os.getenv("FLASK_DEBUG", "0") == "1"

Code explanation:

  • load_dotenv() reads .env into os.environ before you read variables

Warning

Do Not Commit .env

Use .env.example with placeholder keys for teammates:

env
SECRET_KEY=replace-me
DATABASE_URL=mysql+pymysql://user:pass@localhost/dbname

instance/ Folder

Flask supports instance/ for local-only config files:

python
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile("config.py", silent=True)

Place instance/config.py (gitignored):

python
SECRET_KEY = "machine-specific-secret"

Code explanation:

  • instance_relative_config=True keeps secrets outside the importable package

SECRET_KEY in Production

Generate a strong key:

bash
python -c "import secrets; print(secrets.token_hex(32))"

Set on server environment—never hardcode in source:

bash
export SECRET_KEY="paste-generated-value"

If SECRET_KEY leaks, attackers can forge session cookies.

Environment-Based Factory

FAQ

SECRET_KEY missing error?

Flask extensions (sessions, WTF) require it—set in config or env.

DEBUG=True in production?

Never—exposes stack traces and enables debugger risks.

.env not loading?

Call load_dotenv() before reading os.environ; check file path.

Config vs environment variables?

Twelve-factor style: store secrets in env; use config classes for defaults.

Multiple .env files?

.env.production with load_dotenv(".env.production")—load one per deploy target.

SQLAlchemy URI format?

mysql+pymysql://user:password@host:3306/dbname—see MySQL configuration and clients.