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.

  1. 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 --debug
    

    Key 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

    Permalink

  2. 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 the Flask instance, initializes extensions and registers blueprints, instead of creating a global app at 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()' run and 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 app
    

    Key Points

    • create_app() returns a configured app
    • Extensions use ext.init_app(app)
    • Easy test configuration
    • Avoids circular imports

    Permalink

  3. 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, while bp.before_app_request runs 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

    Permalink

  4. Most asked Explain Flask's application context and request context.

    Summary

    The request context makes request and session available during a request; the application context makes current_app and g available. 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 using current_app, extensions like Flask-SQLAlchemy, or url_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 context
    • current_app, g: app context
    • Context locals via contextvars
    • Push contexts manually outside requests

    Permalink

  5. 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.post shortcuts) maps URLs to view functions; converters like int, float, path, uuid and string parse 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 subclass BaseConverter.

    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.post shortcuts (Flask 2.0+)
    • url_for builds URLs by endpoint
    • Trailing slash behavior matters

    Permalink

  6. Most asked How do you access request data and build responses in Flask?

    Summary

    Use the request proxy: 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 a Response object.

    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) returns None instead 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 resp
    

    Key Points

    • request.args, .form, .get_json(), .files
    • Return dict → JSON
    • (body, status, headers) tuples
    • abort() for HTTP errors

    Permalink

  7. 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_SAMESITE and PERMANENT_SESSION_LIFETIME. Rotating SECRET_KEY logs everyone out (SECRET_KEY_FALLBACKS in 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_FALLBACKS for key rotation (3.1)

    Permalink

  8. Most asked How do you use SQLAlchemy with Flask (Flask-SQLAlchemy 3.x)?

    Summary

    Create db = SQLAlchemy(model_class=Base) in an extensions module, call db.init_app(app) in the factory, define models with SQLAlchemy 2.0 typed Mapped columns, and query with db.session.execute(db.select(...)).

    Longer Answer

    Flask-SQLAlchemy scopes db.session to the app context and removes it at teardown. Legacy Model.query still 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; use selectinload.

    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

    Permalink

  9. 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's generate_password_hash or 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_required decorator
    • Hash passwords (scrypt/pbkdf2 via Werkzeug, or Argon2)
    • Flask-JWT-Extended for APIs

    Permalink

  10. Most asked What is `flask.g` and when should you use it?

    Summary

    g is 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

    Permalink

  11. Most asked How does Jinja2 templating work in Flask, including inheritance and autoescaping?

    Summary

    render_template('page.html', **context) renders Jinja2 templates from the templates/ folder. Templates support inheritance ({% extends %}, {% block %}), includes, macros and filters, and autoescaping is on for .html files.

    Longer Answer

    Autoescaping prevents XSS by escaping variables. |safe or Markup disables 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
    • |safe only for trusted HTML
    • Context processors and custom filters

    Permalink

  12. Most asked How do you handle errors in Flask, including JSON APIs?

    Summary

    Register handlers with @app.errorhandler(code_or_exception) (or bp.app_errorhandler) and raise abort(code) or custom exceptions. For APIs, return JSON for HTTPExceptions by handling them generically.

    Longer Answer

    Werkzeug's HTTPException carries code, name and description. 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)}, 409
    

    Key Points

    • @app.errorhandler(404) / custom exceptions
    • Convert HTTPException to JSON for APIs
    • Log unhandled exceptions
    • Never run debug mode in production

    Permalink

  13. Most asked What request hooks does Flask provide and when do they run?

    Summary

    before_request runs before each view (returning a response short-circuits), after_request receives and can modify the response, teardown_request/teardown_appcontext always run at the end (even on errors) for cleanup.

    Longer Answer

    Use before_request for auth checks and loading the current user into g; after_request for headers (CORS, security headers); teardown for closing resources. For WSGI-level middleware (e.g., ProxyFix), wrap app.wsgi_app.

    Key Points

    • before_request can short-circuit
    • after_request modifies response
    • Teardown always runs
    • WSGI middleware via app.wsgi_app

    Permalink

  14. Most asked How do Flask-WTF forms and CSRF protection work?

    Summary

    Flask-WTF integrates WTForms: define a FlaskForm with fields and validators, call form.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 via WTF_CSRF_ENABLED = False. For JSON APIs authenticated by headers rather than cookies, CSRF isn't needed.

    Key Points

    • FlaskForm + validators
    • validate_on_submit()
    • form.hidden_tag() includes token
    • CSRFProtect for global protection

    Permalink

  15. 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 = True propagates exceptions to the test. Use with client: to keep the request context for inspecting session or g after 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() and test_cli_runner()
    • Isolated DB per test
    • TESTING=True

    Permalink

  16. 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). Use ProxyFix so request.remote_addr and URL scheme are correct behind proxies. Set debug=False and a strong SECRET_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 run in prod
    • Nginx for TLS/static files
    • ProxyFix behind proxies
    • Worker type matches workload

    Permalink

  17. 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 environ dict and calls app.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

    Permalink

  18. 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, runs before_request hooks, calls the view, converts the return value to a response, runs after_request hooks, then teardown functions, and pops the contexts.

    Longer Answer

    If a before_request hook 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

    Permalink

  19. 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

    Permalink

  20. 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

    Permalink

  21. How do you manage configuration in Flask?
  22. How do database migrations work with Flask-Migrate?
  23. Does Flask support async views? What are the limitations?
  24. How do you build a REST API in Flask with validation and serialization?
  25. How do you run background tasks in a Flask app?
  26. How do redirects, `url_for` and flash messages work together in Flask?
  27. How do you handle file uploads securely in Flask?
  28. How do you write a custom view decorator such as `@roles_required('admin')`?
  29. Which security measures should a production Flask app have?
  30. How do you secure a Flask JSON API with JWTs?
  31. When would you use gevent workers with Flask, and what are the caveats?
  32. How should transactions be handled in Flask views?
  33. How do you detect and fix N+1 queries in a Flask/SQLAlchemy app?
  34. Why should you release resources in teardown_request rather than after_request in Flask?
  35. How do you add custom CLI commands to a Flask app?
  36. What are Flask signals and when would you use them?
  37. How do you add caching to a Flask application?
  38. How do you enable CORS for a Flask API?
  39. How do you implement rate limiting in Flask?
  40. How does logging work in Flask?
  41. How do you stream a response in Flask?
  42. What are class-based views (`View`, `MethodView`) in Flask?
  43. How do you write your own Flask extension?
  44. What do `flask run --debug` and the reloader do, and why not use them in production?
  45. What is an open redirect and how do you prevent it in a Flask login flow?
  46. How would you implement social login in Flask?
  47. How do you add real-time features (WebSockets) to Flask?
  48. How do you connect to multiple databases with Flask-SQLAlchemy?
  49. What notable changes came in Flask 2.x and 3.x?
  50. How do you customize JSON serialization in Flask?
  51. How do you internationalize a Flask app?
  52. How do you send emails from Flask?
  53. What is Flask-Admin and when is it appropriate?
  54. How do you implement pagination in Flask APIs?
  55. How do you monitor a Flask app in production?
  56. How do you profile and speed up a slow Flask endpoint?
  57. What's a good project structure for a medium-sized Flask app?
  58. How do you containerize a Flask app?
  59. Is Flask thread-safe? How do `request` and `current_app` work across threads?
  60. How do you create a custom URL converter?
  61. How would you version a Flask API?
  62. How does Flask handle HEAD, OPTIONS and 405 Method Not Allowed?
  63. Flask has no built-in dependency injection. How do you structure dependencies for testability?
  64. What is Quart and how does it relate to Flask?
  65. How do you implement Server-Sent Events in Flask?
  66. How do you implement health checks for a Flask service?
  67. Can you use Pydantic with Flask for request validation?
  68. How do you mock external services when testing Flask apps?
  69. How do you test login-protected Flask views?
  70. How are static files served in Flask, and how should they be served in production?
  71. What are `.env` and `.flaskenv` files used for?
  72. What is a scoped session and how does Flask-SQLAlchemy manage it?
  73. How do you tune database connection pooling for a Flask app?
  74. How would you add a GraphQL endpoint to Flask?
  75. How does Flask protect against XSS, and how can it still happen?
  76. What is server-side template injection (SSTI) in Flask?
  77. How do you scale a Flask application horizontally?
  78. How do you run scheduled jobs in a Flask ecosystem?
  79. How do you return dataclasses or ORM objects as JSON in Flask?
  80. What are URL value preprocessors and defaults in Flask?
  81. What's the difference between returning a dict and `jsonify()` in Flask?
  82. How do you render custom 404 and 500 pages in Flask?
  83. How would you incrementally migrate a Flask app to FastAPI?
  84. What is Flask's instance folder?
  85. What's the difference between `request.args`, `request.form`, `request.values` and `request.get_json()`?
  86. How do you set, read and delete cookies in Flask?
  87. How can you generate signed, expiring tokens (e.g., password reset links) in Flask?
  88. Why is starting a thread from a Flask view to do background work risky?
  89. How can you get automatic OpenAPI docs for a Flask API?
  90. Does Flask support ETags and conditional requests?
  91. How would you implement multi-tenancy in Flask?
  92. What steps would you take to upgrade a legacy Flask 1.x app to Flask 3?
  93. How does subdomain routing work in Flask?
  94. What is `app.add_url_rule()` and how does it relate to `@app.route`?
  95. How do you send CSRF tokens with AJAX requests in a Flask-WTF app?
  96. What are context processors and custom template filters in Flask?
  97. How do you let users download files in Flask?
  98. How do you use Redis in a Flask application?
  99. How do type hints help in Flask projects?
  100. What arguments do teardown functions receive and what should they not do?
  101. How should you generate and rotate Flask's `SECRET_KEY`?