The Application Context
When you try to access current_app.config or use url_for() in a script or a background task, you might encounter a RuntimeError: Working outside of application context. This happens because Flask uses an Application Context to keep track of application-level data during a request, CLI command, or other execution cycle.
The application context ensures that the current_app and g proxies point to the correct application instance without requiring you to pass the app object through every function in your codebase.
The current_app Proxy
The current_app object is a FlaskProxy that points to the application handling the current activity. Instead of importing your app instance directly—which can lead to circular imports in larger projects—you use current_app to access configuration, loggers, and other application-level attributes.
from flask import current_app
def get_storage_path():
# Accesses the config of the currently active Flask app
return current_app.config["STORAGE_PATH"]
Internally, current_app is defined in flask.globals as a LocalProxy that looks up the app attribute on the active AppContext.
Storing Data with the g Object
The g object (short for "globals") is a namespace for storing data during an application context. It is commonly used to manage resources like database connections so they can be reused across a single request or CLI command.
In examples/tutorial/flaskr/db.py, Flask uses g to ensure a database connection is only created once per request:
from flask import g, current_app
import sqlite3
def get_db():
if "db" not in g:
g.db = sqlite3.connect(
current_app.config["DATABASE"],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
The g object is an instance of _AppCtxGlobals and is attached to the AppContext. When the context is popped, the data in g is cleared.
Lifecycle of the Context
Flask automatically manages the application context during the lifecycle of an HTTP request or a CLI command.
- Push: At the start of a request, Flask creates an
AppContextand callspush(). This sets the internalcontextvarstoken so thatcurrent_appandgbecome available. - Execution: Your view functions or CLI commands run.
- Pop: When the request ends, Flask calls
pop(). This triggers teardown functions and removes the context from the stack.
Manual Context Management
If you need to access the application context outside of a request—for example, in a unit test or a standalone script—you must push it manually using the app.app_context() context manager.
from myapp import create_app
from flask import current_app
app = create_app()
with app.app_context():
# current_app is now available
print(current_app.name)
The AppContext class in src/flask/ctx.py implements the __enter__ and __exit__ methods to handle this:
def __enter__(self) -> te.Self:
self.push()
return self
def __exit__(self, exc_type, exc_value, tb) -> None:
self.pop(exc_value)
Teardown and Cleanup
When an application context is popped, Flask executes functions registered with @app.teardown_appcontext. These functions run even if an unhandled exception occurred during the request, making them ideal for closing database connections or releasing resources.
You register these functions using the teardown_appcontext decorator:
def close_db(e=None):
db = g.pop("db", None)
if db is not None:
db.close()
app.teardown_appcontext(close_db)
Internally, AppContext.pop calls self.app.do_teardown_appcontext(self, exc), which iterates through all registered teardown functions.
Context Merging in Flask 3.2+
Starting with Flask 3.2, the RequestContext has been merged into AppContext. Previously, Flask maintained two separate stacks. Now, a single AppContext instance handles both application-level data and request-level data (if a request is active).
The AppContext class now includes properties for request and session:
@property
def request(self) -> Request:
if self._request is None:
raise RuntimeError("There is no request in this context.")
return self._request
If you attempt to access request or session when the AppContext was pushed without request data (e.g., in a CLI command), Flask raises a RuntimeError.
URL Generation Pitfalls
A common issue occurs when calling url_for() outside of a request context (e.g., in a background task to generate a link for an email). Because there is no incoming request to determine the host and port, url_for will fail unless the SERVER_NAME configuration variable is set.
# In your config
SERVER_NAME = "example.com"
# In your task
with app.app_context():
url = url_for("index", _external=True)
If SERVER_NAME is provided, the AppContext uses it to initialize a url_adapter even when no request is present, allowing for external URL generation.