Talently
Talently
Flask

Flask

The Python microframework for APIs and lightweight web applications

Flask is a web microframework for Python that provides the minimal tools needed to build web applications and APIs. Its minimalist and unopinionated philosophy grants total freedom over the architecture, making it the preferred choice when simplicity, flexibility, or direct integration with Python's data and machine learning ecosystem is needed.

PythonRESTMicroframeworkAPI

Market demand

Flask has high demand in data science, machine learning, and lightweight API projects. It is widely used to expose ML models as REST APIs and in projects where Python is the primary language but Django's complexity is not needed.

High demand in ML and data scienceWidely used for ML model APIsPopular in startups with Python stack

Technical requirements

Intermediate

Requires good command of Python and web programming concepts such as HTTP, routing, and REST APIs. Unlike Django, Flask requires the developer to make decisions about ORM, authentication, and structure, so knowing Flask's extension ecosystem is important.

Use cases

Real Projects

Flask is used to develop:

  • REST APIs to expose machine learning models
  • Lightweight microservices with specific responsibilities
  • Prototypes and MVPs with Python stack
  • Simple backends for applications with modern frontends

Types of Company

Flask is adopted by:

  • Data science teams exposing models as APIs
  • Startups in prototype phase with Python stack
  • Companies with loosely coupled Python microservices
  • Organizations with research projects requiring quick APIs

Production Scenarios

Flask is widely used in production environments such as:

  • ML model inference APIs with low overhead
  • Microservices with specific and well-defined logic
  • Lightweight backends for internal applications
  • Integration APIs between systems with simple logic

Scalability

Flask offers multiple mechanisms to scale applications:

  • Deployment with Gunicorn or uWSGI as WSGI server
  • Caching with Flask-Caching and Redis
  • Asynchronous tasks with Celery and Redis or RabbitMQ
  • Stateless horizontal scaling with load balancers

Advantages and Disadvantages

Advantages

Extremely lightweight with minimal learning curve for Python developers.

Total freedom over the architecture without imposed conventions.

Direct and natural integration with Python's data and ML ecosystem.

Disadvantages

Requires manual decisions about every component that Django includes by default.

Can lead to inconsistent architectures in teams without defined conventions.

For large applications, the lack of structure can become a maintainability problem.

Comparison

Advantages of Django

  • Complete solution with built-in ORM, admin, and authentication
  • More structure for large teams and projects
  • Less initial configuration time

Considerations

Django is preferable for complete web applications with multiple domains. Flask is more suitable when maximum flexibility is needed, the project is small, or ML integration is a priority.

Basic questions

Flask is preferable when maximum flexibility is needed, the project is small or medium-sized, or the API has a very specific purpose like exposing an ML model. Django includes many tools that can be unnecessary for a simple API.
Flask is preferable when the team already has experience with it, compatibility with existing WSGI extensions is needed, or extreme simplicity is a priority. FastAPI is generally preferable for new APIs where performance and automatic validation add real value.
Flask allows directly importing Python libraries like scikit-learn, TensorFlow, or PyTorch in the same process, without inter-service communication overhead. The integration is direct and the setup minimal, ideal for data science teams that need to expose models quickly.
Through the @app.route() decorator that associates a URL and HTTP methods to a function. Routes can include variables with syntax like and be organized into Blueprints to modularize the application.
They are components that group related routes, handlers, and configuration. They allow modularizing the application into independent sections that are registered with the main app, facilitating organization in growing projects.
Using configuration classes per environment that are loaded based on the FLASK_ENV or FLASK_CONFIG environment variable, complemented with environment variables for sensitive values loaded with python-dotenv in development.
In projects where Python is the language of the entire stack, especially when there is integration with data, ML, or analytics tools. Having the same language in the API and in processing eliminates the need for communication between services in different languages.
The built-in development server is single-threaded, not secure, and not optimized for load. In production, Gunicorn or uWSGI is used as the WSGI server with multiple workers, typically behind a reverse proxy like Nginx.

Technical questions

Flask maintains two contexts: the application context with current_app and g for app lifecycle data, and the request context with request and session for data specific to each HTTP request. Both are automatically created and destroyed in each request cycle.
Using the Flask-JWT-Extended extension that provides decorators like @jwt_required() to protect endpoints, functions to create access and refresh tokens, and automatic handling of authentication errors with consistent JSON responses.
With the Marshmallow extension for defining serialization and validation schemas, or with Pydantic for validation with static typing. Validation is applied before processing business logic, returning structured errors.
Using the Application Factory pattern with create_app() to instantiate the application, organizing each domain into a Blueprint with its routes and handlers, and separating models, services, and validation schemas into independent modules.
They are functions that execute before or after each request respectively. They are used for cross-cutting logic like authentication, logging, database connection management, or response header modification.
Using the @app.errorhandler() decorator to register handlers by HTTP error code or exception type. This centralizes error response formatting and avoids duplicating exception handling logic in each endpoint.
Using Flask-SQLAlchemy which integrates SQLAlchemy with Flask's lifecycle, automatically managing connection and session closing per request. A db object is defined that is imported in models and used in queries.
With Celery as the task queue system and Redis or RabbitMQ as the broker. Tasks are defined with the @celery.task decorator and enqueued from Flask endpoints, being processed in independent workers without blocking the HTTP response.

Advanced questions

By loading the model only once when the Gunicorn worker starts to avoid per-request overhead, using multiple workers with pre-fork, caching frequent predictions with Redis, and considering specialized tools like TorchServe or TensorFlow Serving for very heavy models.
When performance under load becomes a bottleneck, when manual input validation generates frequent errors, or when the team adopts static typing with Python. The migration can be gradual by exposing new endpoints in FastAPI while existing ones remain in Flask.
Using Flask's testing client for endpoint integration tests, pytest with fixtures to set up the test application context, an in-memory SQLite database for database integration tests, and mocks for external dependencies like third-party services.
With Flask-Limiter using Redis as a shared backend in multi-instance environments, defining limits per endpoint based on sensitivity with decorators, and returning informative headers about remaining limits to facilitate client integration.
Using Python's logging module with structured JSON formatting, adding correlation IDs to each request with before_request, integrating metrics with prometheus-flask-exporter, and centralizing logs in tools like ELK Stack or Datadog.
By applying the Application Factory pattern, organizing code into Blueprints by domain, separating into route, service, and repository layers, and defining clear interfaces between layers to facilitate testing and implementation swapping.

Common interview mistakes

Creating the Flask instance directly in the main module makes testing and environment-based configuration difficult. Not knowing create_app() reflects little experience in medium or large-scale Flask projects.
Choosing Flask for a new API without evaluating FastAPI reflects a lack of awareness of the current Python ecosystem. Being able to articulate when Flask is still the right choice over more modern alternatives is expected.
Using flask run or app.run() in production is a serious security and performance error. Not knowing Gunicorn, uWSGI, or the difference between development and production servers reflects a lack of experience in real deployments.
Putting all routes in a single file generates technical debt that is hard to reverse. Not knowing Blueprints or not using them in growing projects reflects inexperience organizing medium-sized Flask projects.
Accessing Flask resources like the database in Celery tasks or scripts without manually creating the application context generates runtime errors. Not understanding Flask's contexts is a sign of superficial understanding of the framework.
Validating manually with conditionals instead of using Marshmallow or Pydantic generates fragile and hard-to-maintain code. Not knowing these tools reflects inexperience building robust Flask APIs.