Interview Q&A · 101 questions · 20 answered publicly
Flask Interview Questions
Ordered by how often they're asked. Sign in free to see every answer, rate your confidence and run timed mock interviews.
-
Most asked What is Flask and what does 'microframework' mean?
Summary
Flask is a lightweight WSGI web framework for Python built on Werkzeug (HTTP/WSGI toolkit) and Jinja2 (templating). 'Micro' means the core stays small and unopinionated, with features like ORM, forms and auth added via extensions.
Longer Answer
Flask gives you routing, request/response objects, sessions, templating, a CLI and a test client. It doesn't choose a database layer, validation library or project structure for you. That flexibility suits APIs, small services and teams that want control, but larger apps need deliberate conventions (blueprints, app factory, extensions).
Code Example
from flask import Flask, jsonify app = Flask(__name__) @app.get("/health") def health(): return jsonify(status="ok") # flask --app app run --debugKey Points
- Built on Werkzeug + Jinja2 (+ Click, ItsDangerous)
- Small core, extensible via extensions
- No built-in ORM or form validation
- WSGI-based; async views supported with limits
Comparison / Tradeoffs
Flask Django FastAPI Philosophy Micro, choose your stack Batteries included API-first, type hints Interface WSGI WSGI/ASGI ASGI ORM Bring your own (SQLAlchemy) Django ORM Bring your own -
Most asked What is the application factory pattern in Flask and why use it?
Summary
An application factory is a
create_app(config=None)function that creates and configures theFlaskinstance, initializes extensions and registers blueprints, instead of creating a globalappat import time.Longer Answer
Benefits: multiple app instances with different configs (tests vs production), no circular imports (extensions are created unbound and attached with
init_app), and no side effects at import.flask --app 'myapp:create_app()' runand Gunicorn ('myapp:create_app()') both support factories.Code Example
# myapp/__init__.py from flask import Flask from .extensions import db, migrate, login_manager def create_app(config_object: str = "myapp.config.ProdConfig") -> Flask: app = Flask(__name__) app.config.from_object(config_object) db.init_app(app) migrate.init_app(app, db) login_manager.init_app(app) from .auth import bp as auth_bp from .orders import bp as orders_bp app.register_blueprint(auth_bp, url_prefix="/auth") app.register_blueprint(orders_bp, url_prefix="/orders") return appKey Points
create_app()returns a configured app- Extensions use
ext.init_app(app) - Easy test configuration
- Avoids circular imports
-
Most asked What are Blueprints in Flask?
Summary
Blueprints group related routes, templates, static files and error handlers into reusable components that are registered on an app (optionally with a URL prefix), so large apps can be organized by feature.
Longer Answer
A blueprint records operations and applies them when registered. You can register the same blueprint multiple times with different prefixes, and nest blueprints (Flask 2.0+).
url_for('orders.detail', id=1)uses the blueprint name as a namespace. Blueprint-specific hooks (bp.before_request) only run for its routes, whilebp.before_app_requestruns for all requests.Code Example
from flask import Blueprint, jsonify bp = Blueprint("orders", __name__) @bp.get("/<int:order_id>") def detail(order_id: int): order = Order.query.get_or_404(order_id) return jsonify(order.to_dict())Key Points
- Feature-based modules
- Registered with
url_prefix - Namespaced endpoints
bp.view - Per-blueprint hooks and error handlers
-
Most asked Explain Flask's application context and request context.
Summary
The request context makes
requestandsessionavailable during a request; the application context makescurrent_appandgavailable. Both are pushed automatically per request and are stored in context-local storage (contextvars), so these proxies are safe per thread/task.Longer Answer
Outside a request (CLI scripts, background jobs, tests) you must push an app context with
with app.app_context():before usingcurrent_app, extensions like Flask-SQLAlchemy, orurl_for.test_request_context()simulates a request. The 'working outside of application context' error means code ran without an active context.Code Example
from flask import current_app def nightly_cleanup(app): with app.app_context(): current_app.logger.info("cleaning up") db.session.execute(db.delete(Session).where(Session.expired)) db.session.commit()Key Points
request,session: request contextcurrent_app,g: app context- Context locals via contextvars
- Push contexts manually outside requests
-
Most asked How does routing work in Flask, including variable rules and HTTP methods?
Summary
@app.route('/path/<converter:name>', methods=[...])(or@app.get/@app.postshortcuts) maps URLs to view functions; converters likeint,float,path,uuidandstringparse and validate URL segments.Longer Answer
url_for('view_name', **params)builds URLs from endpoint names, which avoids hard-coded paths. Routes ending with/redirect requests without the slash; routes without a trailing slash 404 on/path/. Custom converters subclassBaseConverter.Code Example
@app.get("/users/<int:user_id>") def get_user(user_id: int): ... @app.route("/files/<path:filename>", methods=["GET", "DELETE"]) def file_op(filename: str): if request.method == "DELETE": ... url_for("get_user", user_id=5) # '/users/5'Key Points
<int:id>,<path:p>,<uuid:u>converters@app.get/@app.postshortcuts (Flask 2.0+)url_forbuilds URLs by endpoint- Trailing slash behavior matters
-
Most asked How do you access request data and build responses in Flask?
Summary
Use the
requestproxy:request.args(query),request.form(form fields),request.get_json()(JSON body),request.files,request.headers,request.cookies. Return a string, dict (auto-JSON), tuple(body, status, headers)or aResponseobject.Longer Answer
Returning a dict or list (Flask 2.2+) is serialized to JSON automatically.
make_response()lets you set cookies and headers.abort(404)raises an HTTP exception.request.get_json(silent=True)returnsNoneinstead of raising on bad JSON.Code Example
from flask import request, abort, make_response @app.post("/items") def create_item(): data = request.get_json(silent=True) or abort(400, "JSON body required") item = service.create(data) resp = make_response(item.to_dict(), 201) resp.headers["Location"] = url_for("get_item", item_id=item.id) return respKey Points
request.args,.form,.get_json(),.files- Return dict → JSON
(body, status, headers)tuplesabort()for HTTP errors
-
Most asked How do Flask sessions work and what are their security implications?
Summary
By default Flask stores session data client-side in a cookie signed with
SECRET_KEY(via ItsDangerous). Users can read the contents (it's only signed, not encrypted) but cannot modify them without invalidating the signature.Longer Answer
Never put secrets in the default session. Keep it small (cookie size limits). For server-side sessions (revocation, larger data) use Flask-Session with Redis. Configure
SESSION_COOKIE_SECURE,SESSION_COOKIE_HTTPONLY,SESSION_COOKIE_SAMESITEandPERMANENT_SESSION_LIFETIME. RotatingSECRET_KEYlogs everyone out (SECRET_KEY_FALLBACKSin Flask 3.1 eases rotation).Key Points
- Signed, not encrypted, cookie by default
- Don't store secrets in it
- Flask-Session for server-side storage
- Secure cookie flags
SECRET_KEY_FALLBACKSfor key rotation (3.1)
-
Most asked How do you use SQLAlchemy with Flask (Flask-SQLAlchemy 3.x)?
Summary
Create
db = SQLAlchemy(model_class=Base)in an extensions module, calldb.init_app(app)in the factory, define models with SQLAlchemy 2.0 typedMappedcolumns, and query withdb.session.execute(db.select(...)).Longer Answer
Flask-SQLAlchemy scopes
db.sessionto the app context and removes it at teardown. LegacyModel.querystill works but the 2.0 style (db.select,db.get_or_404,db.paginate) is recommended. Use Flask-Migrate (Alembic) for schema migrations. Watch for N+1 queries with relationships; useselectinload.Code Example
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from flask_sqlalchemy import SQLAlchemy class Base(DeclarativeBase): pass db = SQLAlchemy(model_class=Base) class User(db.Model): id: Mapped[int] = mapped_column(primary_key=True) email: Mapped[str] = mapped_column(unique=True) @bp.get("/users/<int:uid>") def get_user(uid: int): user = db.get_or_404(User, uid) return {"id": user.id, "email": user.email} @bp.get("/users") def list_users(): page = db.paginate(db.select(User).order_by(User.id), per_page=20) return {"items": [u.email for u in page.items], "total": page.total}Key Points
db.init_app(app)in the factory- 2.0-style
db.select()queries - Session scoped to app context
- Flask-Migrate for migrations
-
Most asked How do you implement user authentication in Flask?
Summary
For session-based web apps use Flask-Login (user loader,
login_user,logout_user,@login_required,current_user) with hashed passwords (Werkzeug'sgenerate_password_hashor Argon2). For APIs use token-based auth (e.g., Flask-JWT-Extended).Longer Answer
Flask-Login manages the session user ID and 'remember me' cookies; it doesn't handle registration, hashing or permissions. Regenerate the session on login, protect forms with CSRF tokens (Flask-WTF), and rate-limit login attempts.
Code Example
from flask_login import LoginManager, login_user, login_required, current_user from werkzeug.security import check_password_hash login_manager = LoginManager() @login_manager.user_loader def load_user(user_id: str): return db.session.get(User, int(user_id)) @bp.post("/login") def login(): user = db.session.scalar(db.select(User).filter_by(email=request.form["email"])) if user and check_password_hash(user.password_hash, request.form["password"]): login_user(user) return redirect(url_for("dashboard.index")) abort(401) @bp.get("/me") @login_required def me(): return {"email": current_user.email}Key Points
- Flask-Login: session auth helpers
@login_requireddecorator- Hash passwords (scrypt/pbkdf2 via Werkzeug, or Argon2)
- Flask-JWT-Extended for APIs
-
Most asked What is `flask.g` and when should you use it?
Summary
gis a namespace object scoped to the application context (effectively per request) for storing data during a request, such as the current user or a lazily created DB connection.Longer Answer
It's reset for every request, so it isn't for cross-request storage (use a cache or DB). A common pattern is a helper that creates a resource on first use and stores it on
g, with teardown in@app.teardown_appcontext.Code Example
from flask import g def get_db(): if "db" not in g: g.db = connect(current_app.config["DATABASE_URL"]) return g.db @app.teardown_appcontext def close_db(exc): db = g.pop("db", None) if db is not None: db.close()Key Points
- Per-request scratch space
- Reset each request
- Lazy resources + teardown
- Not for cross-request state
-
Most asked How does Jinja2 templating work in Flask, including inheritance and autoescaping?
Summary
render_template('page.html', **context)renders Jinja2 templates from thetemplates/folder. Templates support inheritance ({% extends %},{% block %}), includes, macros and filters, and autoescaping is on for.htmlfiles.Longer Answer
Autoescaping prevents XSS by escaping variables.
|safeorMarkupdisables it, so only use them on trusted or sanitized HTML. Context processors (@app.context_processor) inject variables into all templates. Custom filters are registered with@app.template_filter().Code Example
{# base.html #} <html><body>{% block content %}{% endblock %}</body></html> {# orders.html #} {% extends "base.html" %} {% block content %} <h1>Orders for {{ user.name }}</h1> {% for o in orders %}<li>{{ o.id }} - {{ o.total | round(2) }}</li>{% endfor %} {% endblock %}Key Points
- Template inheritance with blocks
- Autoescaping for
.html |safeonly for trusted HTML- Context processors and custom filters
-
Most asked How do you handle errors in Flask, including JSON APIs?
Summary
Register handlers with
@app.errorhandler(code_or_exception)(orbp.app_errorhandler) and raiseabort(code)or custom exceptions. For APIs, return JSON forHTTPExceptions by handling them generically.Longer Answer
Werkzeug's
HTTPExceptioncarriescode,nameanddescription. A generic handler can convert any of them to JSON. Unhandled exceptions become 500s; log them and return a safe message. In debug mode, Flask shows the interactive debugger, which must never be enabled in production because it allows code execution.Code Example
from werkzeug.exceptions import HTTPException @app.errorhandler(HTTPException) def handle_http(e: HTTPException): return {"error": e.name, "message": e.description}, e.code class InsufficientStock(Exception): pass @app.errorhandler(InsufficientStock) def handle_stock(e): return {"error": "insufficient_stock", "message": str(e)}, 409Key Points
@app.errorhandler(404)/ custom exceptions- Convert
HTTPExceptionto JSON for APIs - Log unhandled exceptions
- Never run debug mode in production
-
Most asked What request hooks does Flask provide and when do they run?
Summary
before_requestruns before each view (returning a response short-circuits),after_requestreceives and can modify the response,teardown_request/teardown_appcontextalways run at the end (even on errors) for cleanup.Longer Answer
Use
before_requestfor auth checks and loading the current user intog;after_requestfor headers (CORS, security headers); teardown for closing resources. For WSGI-level middleware (e.g.,ProxyFix), wrapapp.wsgi_app.Key Points
before_requestcan short-circuitafter_requestmodifies response- Teardown always runs
- WSGI middleware via
app.wsgi_app
-
Most asked How do Flask-WTF forms and CSRF protection work?
Summary
Flask-WTF integrates WTForms: define a
FlaskFormwith fields and validators, callform.validate_on_submit()in the view, and render{{ form.hidden_tag() }}to include the CSRF token, which is validated automatically.Longer Answer
CSRFProtect(app)enables CSRF checks globally, including for non-WTForms POSTs (send the token in a header for AJAX). Disable CSRF in tests viaWTF_CSRF_ENABLED = False. For JSON APIs authenticated by headers rather than cookies, CSRF isn't needed.Key Points
FlaskForm+ validatorsvalidate_on_submit()form.hidden_tag()includes tokenCSRFProtectfor global protection
-
Most asked How do you test a Flask application?
Summary
Create the app via the factory with a testing config in a pytest fixture, use
app.test_client()to make requests,app.test_cli_runner()for CLI commands, and set up an isolated database per test.Longer Answer
TESTING = Truepropagates exceptions to the test. Usewith client:to keep the request context for inspectingsessionorgafter a request. For DBs, create tables in a temporary SQLite DB or run each test in a rolled-back transaction against Postgres.Code Example
import pytest from myapp import create_app from myapp.extensions import db @pytest.fixture def app(): app = create_app("myapp.config.TestConfig") with app.app_context(): db.create_all() yield app db.drop_all() @pytest.fixture def client(app): return app.test_client() def test_create_item(client): r = client.post("/items", json={"name": "Pen"}) assert r.status_code == 201 assert r.get_json()["name"] == "Pen"Key Points
- Factory + test config fixture
test_client()andtest_cli_runner()- Isolated DB per test
TESTING=True
-
Most asked How do you deploy a Flask app to production?
Summary
Run it with a production WSGI server such as Gunicorn, uWSGI or Waitress (never the development server), behind a reverse proxy like Nginx that handles TLS, static files and buffering, typically in containers.
Longer Answer
Gunicorn:
gunicorn -w 4 -b 0.0.0.0:8000 'myapp:create_app()'. Choose workers based on CPU and workload (sync workers for CPU/simple apps; gevent workers or threads for I/O-bound apps). UseProxyFixsorequest.remote_addrand URL scheme are correct behind proxies. Setdebug=Falseand a strongSECRET_KEY.Code Example
from werkzeug.middleware.proxy_fix import ProxyFix app = create_app() app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1) # gunicorn -w 4 --threads 2 -b 0.0.0.0:8000 'wsgi:app'Key Points
- Gunicorn/uWSGI/Waitress, never
flask runin prod - Nginx for TLS/static files
ProxyFixbehind proxies- Worker type matches workload
- Gunicorn/uWSGI/Waitress, never
-
Most asked What is WSGI and what role does Werkzeug play in Flask?
Summary
WSGI (PEP 3333) is the standard interface between Python web servers and apps: the app is a callable
app(environ, start_response). Werkzeug is the WSGI toolkit Flask uses for request/response objects, routing, the dev server, the debugger and utilities.Longer Answer
When Gunicorn receives a request it builds the
environdict and callsapp.wsgi_app. Flask pushes contexts, dispatches to the view and returns a response iterable. Because the interface is synchronous, a WSGI worker handles one request at a time (per thread/greenlet).Code Example
def simple_wsgi_app(environ, start_response): start_response("200 OK", [("Content-Type", "text/plain")]) return [b"Hello from WSGI"]Key Points
app(environ, start_response)- Werkzeug: Request/Response, routing, debugger
- Sync request/response model
- Middleware wraps
wsgi_app
-
Most asked Walk through the lifecycle of a request in Flask.
Summary
The WSGI server calls
app.wsgi_app; Flask creates a request context (which pushes an app context), matches the URL, runsbefore_requesthooks, calls the view, converts the return value to a response, runsafter_requesthooks, then teardown functions, and pops the contexts.Longer Answer
If a
before_requesthook returns a value, the view is skipped. Exceptions are routed to error handlers;teardown_*functions run even when errors occur. Signals fire at key points (request_started,request_finished).Key Points
- Contexts pushed → URL matched
- before_request → view → after_request
- Teardown always runs
- Error handlers on exceptions
Deep dive: Request Lifecycle course: Flask: Contexts, Hooks and Teardown
-
Most asked When would you choose Flask over FastAPI or Django?
Summary
Choose Flask for server-rendered or mixed apps where you want a small, flexible core and a mature ecosystem; FastAPI for typed, async-first JSON APIs with automatic OpenAPI; Django when you want an integrated ORM, admin, auth and conventions.
Longer Answer
Flask shines for small-to-medium apps, internal tools, prototypes and teams that want to choose components. Its sync model is simple and works well with most libraries. FastAPI is better for high-concurrency I/O APIs; Django for content-heavy or admin-heavy products.
Key Points
- Flask: flexible, mature, sync-first
- FastAPI: typed async APIs
- Django: batteries included
- Choose by team and domain
-
Most asked How do you prevent SQL injection in Flask apps?
Summary
Use SQLAlchemy's query building or bound parameters (
text('... WHERE id = :id')with params) and never build SQL with f-strings from user input; allow-list identifiers like sort columns.Longer Answer
ORMs parameterize values automatically, but raw
text()with string interpolation reintroduces risk. Validate and map user-chosen sort fields to known columns.Key Points
- ORM / bound parameters
- No f-string SQL
- Allow-list identifiers
- How do you manage configuration in Flask?
- How do database migrations work with Flask-Migrate?
- Does Flask support async views? What are the limitations?
- How do you build a REST API in Flask with validation and serialization?
- How do you run background tasks in a Flask app?
- How do redirects, `url_for` and flash messages work together in Flask?
- How do you handle file uploads securely in Flask?
- How do you write a custom view decorator such as `@roles_required('admin')`?
- Which security measures should a production Flask app have?
- How do you secure a Flask JSON API with JWTs?
- When would you use gevent workers with Flask, and what are the caveats?
- How should transactions be handled in Flask views?
- How do you detect and fix N+1 queries in a Flask/SQLAlchemy app?
- Why should you release resources in teardown_request rather than after_request in Flask?
- How do you add custom CLI commands to a Flask app?
- What are Flask signals and when would you use them?
- How do you add caching to a Flask application?
- How do you enable CORS for a Flask API?
- How do you implement rate limiting in Flask?
- How does logging work in Flask?
- How do you stream a response in Flask?
- What are class-based views (`View`, `MethodView`) in Flask?
- How do you write your own Flask extension?
- What do `flask run --debug` and the reloader do, and why not use them in production?
- What is an open redirect and how do you prevent it in a Flask login flow?
- How would you implement social login in Flask?
- How do you add real-time features (WebSockets) to Flask?
- How do you connect to multiple databases with Flask-SQLAlchemy?
- What notable changes came in Flask 2.x and 3.x?
- How do you customize JSON serialization in Flask?
- How do you internationalize a Flask app?
- How do you send emails from Flask?
- What is Flask-Admin and when is it appropriate?
- How do you implement pagination in Flask APIs?
- How do you monitor a Flask app in production?
- How do you profile and speed up a slow Flask endpoint?
- What's a good project structure for a medium-sized Flask app?
- How do you containerize a Flask app?
- Is Flask thread-safe? How do `request` and `current_app` work across threads?
- How do you create a custom URL converter?
- How would you version a Flask API?
- How does Flask handle HEAD, OPTIONS and 405 Method Not Allowed?
- Flask has no built-in dependency injection. How do you structure dependencies for testability?
- What is Quart and how does it relate to Flask?
- How do you implement Server-Sent Events in Flask?
- How do you implement health checks for a Flask service?
- Can you use Pydantic with Flask for request validation?
- How do you mock external services when testing Flask apps?
- How do you test login-protected Flask views?
- How are static files served in Flask, and how should they be served in production?
- What are `.env` and `.flaskenv` files used for?
- What is a scoped session and how does Flask-SQLAlchemy manage it?
- How do you tune database connection pooling for a Flask app?
- How would you add a GraphQL endpoint to Flask?
- How does Flask protect against XSS, and how can it still happen?
- What is server-side template injection (SSTI) in Flask?
- How do you scale a Flask application horizontally?
- How do you run scheduled jobs in a Flask ecosystem?
- How do you return dataclasses or ORM objects as JSON in Flask?
- What are URL value preprocessors and defaults in Flask?
- What's the difference between returning a dict and `jsonify()` in Flask?
- How do you render custom 404 and 500 pages in Flask?
- How would you incrementally migrate a Flask app to FastAPI?
- What is Flask's instance folder?
- What's the difference between `request.args`, `request.form`, `request.values` and `request.get_json()`?
- How do you set, read and delete cookies in Flask?
- How can you generate signed, expiring tokens (e.g., password reset links) in Flask?
- Why is starting a thread from a Flask view to do background work risky?
- How can you get automatic OpenAPI docs for a Flask API?
- Does Flask support ETags and conditional requests?
- How would you implement multi-tenancy in Flask?
- What steps would you take to upgrade a legacy Flask 1.x app to Flask 3?
- How does subdomain routing work in Flask?
- What is `app.add_url_rule()` and how does it relate to `@app.route`?
- How do you send CSRF tokens with AJAX requests in a Flask-WTF app?
- What are context processors and custom template filters in Flask?
- How do you let users download files in Flask?
- How do you use Redis in a Flask application?
- How do type hints help in Flask projects?
- What arguments do teardown functions receive and what should they not do?
- How should you generate and rotate Flask's `SECRET_KEY`?