Your instinct to use environment variables is correct. However, there is some danger of running unit tests with the wrong db. Also, you may not want to connect_db with every request and everywhere you want to use db. You can use a config directory and environment variables which you set explicitly. This is the best I've come up with so far.

run.py
shell.py

config/__init__.py
config/test.py
config/postgres.py
...

main/__init__.py
main/someapp/__init__.py
main/someapp/models.py

...
main/tests/__init__.py
main/tests/testutils.py

so, the config files may be:

# config/test.py
SQLALCHEMY_DATABASE_URI = "sqlite://"

and

# config/postgres.py
SQLALCHEMY_DATABASE_URI = 'postgresql://user:pw@localhost/somedb'

So, I can explicitly set the db in my base TestCase:

import os
from flask.ext.testing import TestCase

os.environ["DIAG_CONFIG_MODULE"] = "config.test"
from main import app, db


class SQLAlchemyTest(TestCase):

    def create_app(self):
        return app

    def setUp(self):
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()

Then, the main/__init__.py, for me:

import os

from flask import Flask, render_template, g
from flask.ext.sqlalchemy import SQLAlchemy

# by default, let's use a DB we don't care about
# but, we can override if we want
config_obj = os.environ.get("DIAG_CONFIG_MODULE", "config.test")
app = Flask(__name__)
app.config.from_object(config_obj)
db = SQLAlchemy(app)

@app.before_request
def before_request():
    g.db = db
    g.app = app

# ...
@app.route('/', methods=['GET'])
def get():
    return render_template('home.html')
# ...    
from main.someapp.api import mod as someappmod
app.register_blueprint(someappmod)

Then, in the other files, where I know what config I want to run, potentially:

# run.py
import os
os.environ["DIAG_CONFIG_MODULE"] = "config.postgres"
from main import app
app.run(debug=True)

and

# shell.py
import os
os.environ["DIAG_CONFIG_MODULE"] = "config.postgres"

from main import app, db
from main.symdiag.models import *
from main.auth.models import *
print sorted(k for k in locals().keys() if not k.startswith("_"))
import IPython
IPython.embed()

Maybe .. best so far :P.

Answer from Skylar Saveland on Stack Overflow
🌐
Flask-SQLAlchemy
flask-sqlalchemy.readthedocs.io › en › stable › config
Configuration — Flask-SQLAlchemy Documentation (3.1.x)
Or it can be a dict of arguments, including the url key, that will be passed to sqlalchemy.create_engine(). The None key can be used to configure the default bind, but SQLALCHEMY_ENGINE_OPTIONS and SQLALCHEMY_DATABASE_URI take precedence. At least one of this and SQLALCHEMY_DATABASE_URI must be set. ... Added in version 0.12. ... The default value for echo and echo_pool for every engine. This is useful to quickly debug the connections and queries issued from SQLAlchemy. ... Changed in version 3.0: Sets echo_pool in addition to echo. flask_sqlalchemy.config.SQLALCHEMY_RECORD_QUERIES¶
🌐
Flask-SQLAlchemy
flask-sqlalchemy.readthedocs.io › en › stable › quickstart
Quick Start — Flask-SQLAlchemy Documentation (3.1.x)
Create your Flask application object, load any config, and then initialize the SQLAlchemy extension class with the application by calling db.init_app. This example connects to a SQLite database, which is stored in the app’s instance folder. # create the app app = Flask(__name__) # configure ...
🌐
DigitalOcean
digitalocean.com › community › tutorials › how-to-use-flask-sqlalchemy-to-interact-with-databases-in-a-flask-application
Interact with Databases in Flask Using Flask-SQLAlchemy | DigitalOcean
October 21, 2025 - After configuring SQLAlchemy by setting a database URI and disabling tracking, you create a database object using the SQLAlchemy class, passing the application instance to connect your Flask application with SQLAlchemy. You store your database object in a variable called db.
🌐
Teclado
rest-apis-flask.teclado.com › configure flask-sqlalchemy
Configure Flask-SQLAlchemy | REST APIs with Flask and Python
import os from flask import Flask from flask_smorest import Api from db import db import models from resources.item import blp as ItemBlueprint from resources.store import blp as StoreBlueprint def create_app(db_url=None): app = Flask(__name__) app.config["PROPAGATE_EXCEPTIONS"] = True app.config["API_TITLE"] = "Stores REST API" app.config["API_VERSION"] = "v1" app.config["OPENAPI_VERSION"] = "3.0.3" app.config["OPENAPI_URL_PREFIX"] = "/" app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui" app.config[ "OPENAPI_SWAGGER_UI_URL" ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/" app.config["SQLALCHEMY_DATABASE_URI"] = db_url or os.getenv("DATABASE_URL", "sqlite:///data.db") app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False db.init_app(app) api = Api(app) with app.app_context(): db.create_all() api.register_blueprint(ItemBlueprint) api.register_blueprint(StoreBlueprint) return app
🌐
Hackers and Slackers
hackersandslackers.com › flask-sqlalchemy-database-models
Connect Flask to a Database with Flask-SQLAlchemy
August 20, 2024 - SQLALCHEMY_ECHO: When set to 'True', Flask-SQLAlchemy will log all database activity to Python's stderr for debugging purposes. SQLALCHEMY_TRACK_MODIFICATIONS: Honestly, I just always set this to 'False,' otherwise an obnoxious warning appears every time you run your app reminding you that this option takes a lot of system resources. Those are the big ones we should worry about. If you're into some next-level database shit, there are a few other pro-mode configuration variables which you can find here.
Top answer
1 of 3
12

Your instinct to use environment variables is correct. However, there is some danger of running unit tests with the wrong db. Also, you may not want to connect_db with every request and everywhere you want to use db. You can use a config directory and environment variables which you set explicitly. This is the best I've come up with so far.

run.py
shell.py

config/__init__.py
config/test.py
config/postgres.py
...

main/__init__.py
main/someapp/__init__.py
main/someapp/models.py

...
main/tests/__init__.py
main/tests/testutils.py

so, the config files may be:

# config/test.py
SQLALCHEMY_DATABASE_URI = "sqlite://"

and

# config/postgres.py
SQLALCHEMY_DATABASE_URI = 'postgresql://user:pw@localhost/somedb'

So, I can explicitly set the db in my base TestCase:

import os
from flask.ext.testing import TestCase

os.environ["DIAG_CONFIG_MODULE"] = "config.test"
from main import app, db


class SQLAlchemyTest(TestCase):

    def create_app(self):
        return app

    def setUp(self):
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()

Then, the main/__init__.py, for me:

import os

from flask import Flask, render_template, g
from flask.ext.sqlalchemy import SQLAlchemy

# by default, let's use a DB we don't care about
# but, we can override if we want
config_obj = os.environ.get("DIAG_CONFIG_MODULE", "config.test")
app = Flask(__name__)
app.config.from_object(config_obj)
db = SQLAlchemy(app)

@app.before_request
def before_request():
    g.db = db
    g.app = app

# ...
@app.route('/', methods=['GET'])
def get():
    return render_template('home.html')
# ...    
from main.someapp.api import mod as someappmod
app.register_blueprint(someappmod)

Then, in the other files, where I know what config I want to run, potentially:

# run.py
import os
os.environ["DIAG_CONFIG_MODULE"] = "config.postgres"
from main import app
app.run(debug=True)

and

# shell.py
import os
os.environ["DIAG_CONFIG_MODULE"] = "config.postgres"

from main import app, db
from main.symdiag.models import *
from main.auth.models import *
print sorted(k for k in locals().keys() if not k.startswith("_"))
import IPython
IPython.embed()

Maybe .. best so far :P.

2 of 3
6

You won't want to make connecting to the db happen at import time. Go ahead and configure your app at import time because you can always tweak the configuration in your tests before attempting to test or run your app. In the example below you'll have your db connection behind some functions that use the application config so in a unittest you can actually change the db connection to point to a different file and then go ahead and connect explicitly in your setup.

Say you have a myapp package containing myapp.py which looks like:

# myapp/myapp.py
from __future__ import with_statement
from sqlite3 import dbapi2 as sqlite3
from contextlib import closing
from flask import Flask, request, session, g, redirect, url_for, abort, \
     render_template, flash

# configuration
DATABASE = '/tmp/flaskr.db'
DEBUG = True
SECRET_KEY = 'development key'
USERNAME = 'admin'
PASSWORD = 'default'

# create our little application :)
app = Flask(__name__)
app.config.from_object(__name__)
app.config.from_envvar('MYAPP_SETTINGS', silent=True)

def connect_db():
    """Returns a new connection to the database."""
    return sqlite3.connect(app.config['DATABASE'])


def init_db():
    """Creates the database tables."""
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql') as f:
            db.cursor().executescript(f.read())
        db.commit()


@app.before_request
def before_request():
    """Make sure we are connected to the database each request."""
    g.db = connect_db()


@app.after_request
def after_request(response):
    """Closes the database again at the end of the request."""
    g.db.close()
    return response

@app.route('/')
def show_entries():
    cur = g.db.execute('select title, text from entries order by id desc')
    entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
    return render_template('show_entries.html', entries=entries)

if __name__=="__main__":
    app.run()

Your test file myapp/test_myapp.py will look like this:

import os
import myapp
import unittest
import tempfile

class MyappTestCase(unittest.TestCase):

    def setUp(self):
        self.db_fd, myapp.app.config['DATABASE'] = tempfile.mkstemp()
        self.app = myapp.app.test_client()
        myapp.init_db()

    def tearDown(self):
        os.close(self.db_fd)
        os.unlink(myapp.app.config['DATABASE'])

    def test_empty_db(self):
        rv = self.app.get('/')
        assert 'No entries here so far' in rv.data

Of course if you'd like to use SQLAlchemy you'll have to update the connect_db and init_db functions appropriately but hopefully you get the idea.

🌐
OneUptime
oneuptime.com › home › blog › how to use flask with sqlalchemy
How to Use Flask with SQLAlchemy
January 26, 2026 - # app/__init__.py from flask import Flask from flask_sqlalchemy import SQLAlchemy # Create db instance without app db = SQLAlchemy() def create_app(config_name='development'): """Application factory function""" app = Flask(__name__) # Load configuration based on environment if config_name == 'development': app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///dev.db' app.config['SQLALCHEMY_ECHO'] = True elif config_name == 'testing': app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:' app.config['SQLALCHEMY_ECHO'] = False elif config_name == 'production': app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') app.config['SQLALCHEMY_ECHO'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Initialize db with app db.init_app(app) # Register blueprints from app.routes import main_bp app.register_blueprint(main_bp) return app
Find elsewhere
🌐
Stack Overflow
stackoverflow.com › questions › 76909383 › how-to-setup-sql-alchemy-in-a-flask-project-properly
python - How to setup SQL ALchemy in a Flask project properly? - Stack Overflow
More specifically, the Flask Mega Tutorial (blog.miguelgrinberg.com/post/…) will walk you through how to use blueprints and blueprint-specific models. Dave W. Smith – Dave W. Smith · 2023-08-15 23:54:00 +00:00 Commented Aug 15, 2023 at 23:54 ... You can separate SQLAlchemy initialization and models, then import what you need inside app.py.
🌐
Flask
flask.palletsprojects.com › en › stable › patterns › sqlalchemy
SQLAlchemy in Flask — Flask Documentation (3.1.x)
To define your models, just subclass the Base class that was created by the code above. If you are wondering why we don’t have to care about threads here (like we did in the SQLite3 example above with the g object): that’s because SQLAlchemy does that for us already with the scoped_session.
🌐
DevCamp
devcamp.com › trails › python-api-development-with-flask › campsites › hello-flask › guides › creating-sqlite-database-flask-sqlalchemy
Creating a SQLite Database in Flask with SQLAlchemy
Now, this is technically not a dictionary. It is a configuration variable, but you can think of it as performing a look up and then setting a value in our application. So I'm gonna say: basedir = os.path.abspath(os.path.dirname(__file__)) app.config['SQLALCHEMY_DATABASE_URI']
🌐
AppSignal
blog.appsignal.com › 2025 › 02 › 26 › an-introduction-to-flask-sqlalchemy-in-python.html
An Introduction to Flask-SQLAlchemy in Python | AppSignal Blog
February 26, 2025 - You can configure your database connection and other settings through Flask’s configuration system, making it easy to manage different environments (for example: development, testing, and production environments). Automatic tables creation: If you are connecting to a database that already has tables, Flask-SQLAlchemy can automatically create tables based on your defined models when the application starts.
🌐
Medium
medium.com › analytics-vidhya › flask-development-part-4-database-configuration-648b11f708a5
Flask Development Part 4: Database Configuration | by Shawn Hymers | Analytics Vidhya | Medium
April 11, 2021 - from flask import Flask from flask_login import UserMixin from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__, template_folder='../templates')app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' db = SQLAlchemy(app)class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key = True) username = db.Column(db.String(20), unique = True, nullable = False) email = db.Column(db.String(120), unique = True, nullable = False) password = db.Column(db.String(60), nullable = False)
🌐
Arch Linux Man Pages
man.archlinux.org › man › extra › python-flask-sqlalchemy › python-flask-sqlalchemy.1.en
python-flask-sqlalchemy(1) — Arch manual pages
Flask-SQLAlchemy simplifies how binds work by associating each engine with a short string, a "bind key", and then associating each model and table with a bind key. The session will choose what engine to use for a query based on the bind key of the thing being queried.
🌐
Miguel Grinberg
blog.miguelgrinberg.com › post › the-flask-mega-tutorial-part-iv-database
The Flask Mega-Tutorial, Part IV: Database - miguelgrinberg.com
The nice thing about flask shell is not only that it pre-imports app, but that you can also configure a "shell context", which is a list of other symbols to pre-import. The following function in microblog.py creates a shell context that adds the database instance and models to the shell session: import sqlalchemy as sa import sqlalchemy.orm as so from app import app, db from app.models import User, Post @app.shell_context_processor def make_shell_context(): return {'sa': sa, 'so': so, 'db': db, 'User': User, 'Post': Post}
🌐
GeeksforGeeks
geeksforgeeks.org › python › connect-flask-to-a-database-with-flask-sqlalchemy
Flask SQLAlchemy Tutorial for Database - GeeksforGeeks
2 weeks ago - Flask doesn’t have a built-in way to handle databases, so it relies on SQLAlchemy, a library that makes working with databases easier.
🌐
Flask-SQLAlchemy
flask-sqlalchemy.readthedocs.io › en › stable
Flask-SQLAlchemy — Flask-SQLAlchemy Documentation (3.1.x)
It simplifies using SQLAlchemy with Flask by setting up common objects and patterns for using those objects, such as a session tied to each web request, models, and engines.
🌐
Architecture
architecture.pub › articles › 2197221151.html
Installation and setting of flask Sqlalchemy
install flask-sqlalchemy pip install ... must be saved to Flask Configuration object SQLALCHEMY_DATABASE_URI Key in app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test' Other settings: # Dynamic tracking changes settings....