According to the 2020 JetBrains Python Developers Survey, Django and Flask are by far the two most popular Python web frameworks. It’s no surprise that Flask moved past Django to take the top spot considering that the web development industry has been trending toward smaller frameworks, microservices, and “serverless” platforms over the past five or so years.
Or perhaps this has less to do with industry trends and more to do with JetBrains users?
Django and Flask have mature communities, are widely supported and popular, and offer productive approaches to application development, letting you focus your time and energy on the unique parts of your application rather than the core scaffolding. In the end, both frameworks are used to develop web applications. The key difference lies in how they achieve this goal. Think of Django as a car and Flask as a bike. Both can get you from point A to point B, but their approaches are quite different. Each has its own best use cases. The same goes for Django and Flask.
In this article, we’ll look at the best use cases for Django and Flask along with what makes them unique, from an educational and development standpoint.
Django and Flask are both free, open source, Python-based web frameworks designed for building web applications.
When compared to Flask, Django embraces stability as well as a “batteries included” approach where a number of batteries (i.e., tools, patterns, features, and functionality) are provided out-of-the-box. In terms of stability, Django generally has longer, more rigid release cycles. So, Django releases come with fewer shiny new features but have stronger backwards compatibility.
Based on Werkzeug, Flask handles the core scaffolding well. Out-of-the-box, you get URL routing, request and error handling, templating, cookies, support for unit testing, a debugger, and a development server. Since most web applications need quite a bit more (like an ORM, authentication and authorization, to name a few), you get to decide how you want to build your application. Whether you leverage third-party extensions or customize the code yourself, Flask stays out of your way for this. It’s much more flexible than Django. There’s also much less surface area open to attack and less code to review if you need to crack open the hood and look at the source code.
I highly encourage you to read and review the Flask source code. Clean, clear, and concise — it’s an excellent example of well-structured Python code.
Next, let’s compare Flask and Django based on the features that ship with the core framework.
Django includes a simple yet powerful ORM (Object Relational Mapping) that supports a number of relational databases out-of-the-box: SQLite, PostgreSQL, MySQL, MariaDB, and Oracle. The ORM provides support for generating and managing database migrations. It’s also fairly easy to create forms, views, and templates based on the data models, which is perfect for your typical CRUD web application. While it does have some shortcomings, it’s good enough for the majority of web applications.
Flask makes no assumptions about how data is stored, but there are plenty of libraries and extensions available to help with that:
In conclusion, if you’re using a relational database, Django makes it much easier to get started since it has a built-in ORM and migration management tool. If, however, you’re using a non-relational database or would like to use a different ORM like SQLAlchemy, Django will fight you almost every step of the way. Plus, you’ll most likely not be able to take advantage of the Django admin, model forms, or DRF model serializers.
Flask stays out of your way, giving you the freedom to pick and chose the ORM (or ODM) that works best with your application. Freedom comes at a price, though: There’s a higher learning curve and more room for error since you’re managing these pieces yourself.
The more you do on your own the more mistakes you’ll make, especially as things scale.
Since most web applications require authentication (who are you?) and authorization (what are you allowed to do?), Django provides this functionality along with account management and support for sessions (via the User model) out-of-the-box. Flask provides support for cookie-based sessions, but you’ll have to turn to the extension network for account management, authentication, and authorization.
Django comes with a functional admin panel, which is a web application that provides a user interface for managing data based on your models. This is another area where Django shines. It allows you to quickly perform CRUD operations against your models as you build out an application without writing any extra code. Again, Flask does not ship with anything like this, but the Flask-Admin extension offers all of the same functionality and a lot more:
Django does lots of things automatically.
Flask philosophy is slightly different — explicit is better than implicit. If something should be initialized, it should be initialized by the developer.
Flask-Admin follows this convention. It is up to you, as a developer, to tell Flask-Admin what should be displayed and how.
Sometimes this will require writing a bit of boilerplate code, but it will pay off in the future, especially if you have to implement some custom logic.
Flask-Admin supports a number of database backends, like SQLAlchemy, Peewee, MongoEngine, to name a few. You can add your own backends as well. It can also be used with (or without) the popular Flask auth extensions:
Routing and Views
Both frameworks allow you to map URLs to views and support function and class-based views.
When a request matches a URL pattern, the request object, which holds the HTTP request information, is passed to a view and that view is then invoked. Anytime you need access to the request object, you must explicitly pass it around.
URLs and views are defined in separate files — urls.py and views.py, respectively.
At it its core, Flask uses Werkzeug, which provides URL routing and request/response handling.
The request object is global in Flask, so you can access it much easier (as long as you import it). URLs are generally defined along with the view (via a decorator), but they can be separated out into a centralized location similar to the Django pattern.
Did you take note of the difference in how Django and Flask both handle the request object? In general, Flask tends to be more explicit with things, but in this case it’s the opposite: Django forces you to explicitly pass around the request object while Flask’s request object is just magically available. This is one of the difficult parts with Flask, especially for those that are new to the framework from a similar style framework like Express.js.
Forms, another essential part of most web applications, come packaged with Django. This includes input handling and client and server-side validation along with the handling of various security concerns like cross-site request forgery (CSRF), cross-site scripting (XSS), and SQL injection. They can be created from the data models (via ModelForms) and integrate well with the admin panel.
Flask doesn’t support forms by default, but the powerful Flask-WTF extension integrates Flask with WTForms. WTForms-Alchemy can be used to automatically create forms based on SQLAlchemy models, bridging the gap between forms and the ORM much like Django’s ModelForm.
With regard to project structure, as your apps get more complicated, both frameworks make it easy for you to break them up by grouping related files together that exhibit similar functionality. So, you could, for example, group all user-related functionality together, which can include the routes, views, forms, templates, and static assets.
Django apps are more complex than Flask blueprints, but they tend to be easier to work with and re-use once setup. Plus, due to the urls.py, models.py, and views.py convention — consistent project structure! — you can add new developers to a Django project fairly easily. Blueprints, meanwhile, are simpler and easier to get up and running.
Templates and Static Files
Template engines allow you to dynamically inject information onto an HTML page from the backend. Flask uses Jinja2 by default while Django has its own templating engine. They’re fairly similar in terms of syntax and feature sets. You can also use Jinja2 with Django.
Both frameworks have static file handling support as well:
Django comes with a handy management command for collecting all static files and placing them in a central location for production deployments.
Django supports asynchronous handlers with the introduction of Django 3.1. A view can be made asynchronous by using the keyword
async. The async support is available to middlewares also. If you need to make a synchronous call inside an async view, you can use the sync_to_async function/decorator. This can be used to interact with other parts of Django that don’t support async yet, like the ORM and cache layer.
Both frameworks have in-built support for testing.
For unit testing, they both leverage Python’s unittest framework. Each of them also support a test client that you can send requests to and then inspect and validate parts of the response.
In terms of extensions, if you like how the unittest framework works, check out Flask-Testing. On the other hand, the pytest-flask extension adds pytest support to Flask. For Django, check out pytest-django.
There are several other features not already mentioned that come with Django but not Flask:
As mentioned, Django has built-in protection against a number of common attack vectors like CSRF, XSS, and SQL injection. These security measures help protect against vulnerabilities in your code. The Django development team also proactively discloses and quickly fixes known security vulnerabilities. Flask, on the other hand, has a much smaller code base so there’s less surface area open to attack. However, you’ll need to address and fix security vulnerabilities in your hand-crafted app code as they surface.
At the end of the day, you’re only as secure as your weakest link. Since Flask is much more reliant on third-party extensions, applications will only be as secure as the least-secure extension. This puts more pressure on your development team to maintain security by evaluating and monitoring third-party libraries and extensions. Keeping them up-to-date is the most important (and often the hardest) thing here since each extension has its own development team, documentation, and release cycles. In some cases, there may only be one or two developers maintaining a particular extension. When evaluating one extension over another be sure to review GitHub issues to see how long it generally takes for maintainers to respond to critical issues.
This does not mean that Django is inherently more secure than Flask; it’s just easier to secure upfront and maintain during the life of your application.
- Flask Security Considerations
- Security in Django
- Securing Flask web applications
- Protect Your Django Web Application From Security Threats
Flask, by design, is much more flexible than Django, and it’s meant to be extended. Because of this, Flask generally takes longer to set up since you’ll have to add the appropriate extensions based on business needs — e.g., ORM, permissions, authentication, and so forth. This upfront cost results in more flexibility down the road for applications that don’t fit the standard Django model.
Be careful with this, though. Flexibility gives developers more freedom and control, but this can slow down development especially for larger teams since a lot more decisions need to made.
Developers love having the freedom to do whatever they want to solve a problem. Since Flask doesn’t provide many constraints or opinions on how an app is developed, developer’s get to introduce their own. The result is that two Flask apps that are functionally interchangeable compared side-by-side will be structured differently. Thus, you need a more mature team that understands design patterns, scalability, and the importance of testing to handle such flexibility.
Learn patterns, not languages or frameworks.
Regardless of whether your end goal is to learn Flask or Django, start with Flask. It’s a great tool for learning web development fundamentals and best practices along with the core pieces of a web framework that are common to almost all frameworks.
- Flask is lighter and much more explicit than Django. So, if you’re new to web development but not to Python, you’ll find it much easier to develop in Flask since it will feel much like you’re working with vanilla Python to define request handlers and views and what not.
- Django has a lot of overhead. From the project structure to the settings to installing a number of nuts and bolts that you don’t know anything about, you’ll get lost and end up learning more about Django itself than the actual fundamentals.
In almost all cases, it’s recommended to learn Flask before Django. The only time you should deviate from that is when you just need to get an app up quick to satisfy some external stakeholder. Just be sure to work your way back to Flask to learn the basics at some point.
Django and Flask have strong open source communities.
GitHub stats as of February 24th, 2022:
*number of times the dependency is used by other repositories
For more, review Open Hub’s Open source comparison of Django and Flask.
Stack Overflow questions as of February 24th, 2022:
What can we conclude here?
- Both communities are very active
- Django is older and has a lot more contributors
- Flask is used by more projects
- There’s more content out there on Django
To really compare these frameworks (or ecosystems) from an open source perspective, you’d have to account for Jinja2 and Werkzeug along with some of the core Flask libraries and extensions like SQLAlchemy / Flask-SQLAlchemy, Alembic / Flask-Alembic, and WTForms / Flask-WTF.
Since the core Flask functionality is spread out across multiple projects it’s harder for the community to create and develop the necessary synergy across projects to sustain momentum. For example, Flask doesn’t have a single, de-facto extension for creating RESTful APIs; there are (arguably) four popular extensions as of February 2022:
What’s more, in order to find these extensions you need to have some pretty solid information retrieval skills. You’ll have to filter through all the un-maintained extensions out there and articles that reference them. In fact, there are so many different extension projects for RESTful APIs that it’s often easier to just roll your own and open source it. At that point, you’ll probably maintain it for a bit but eventually it will become part of the problem rather than a solution.
- The Django community is not immune to this by any means. It’s just less of an issue since it handles almost everything required to build and secure a standard web app out-of-the-box.
For more on this review the “Open source momentum” section from Django vs Flask: A Practictioner’s Perspective:
By not having a united front, the opportunity for synergetic efforts that bridge across extensions fail to materialize, creating extensions that are porous. This leaves devs to fill in the blanks for all-inclusive functionality that’d already be working had they just picked a different tool for the job.
Despite both Python and Django’s popularity, it’s hard to hire Django developers. They’re difficult to find and retain since they’re in such high demand, and they’re typically more on the senior side so they can be quite expensive. There’s also not a lot of new, aspiring web developers learning Django since the industry is focused more on smaller frameworks and the framework itself is difficult to learn.
- Difficult to learn: There’s a surprising lack of beginner-friendly Django tutorials. Even the Django documentation, which is incredibly comprehensive, and the infamous polls tutorial are not designed for beginners.
Flask can be difficult to hire for too, but it tends to be easier than Django since it’s a light weight framework with fewer abstraction layers. A strong developer with experience in a similar framework in a different language, like Express.js or Sinatra, can get up to speed with a Flask app fairly quickly. When hiring such developers, focus your search on those that understand design patterns and fundamental software principles rather than the languages or frameworks they know.
Be sure to take your project’s individual needs into account when you’re deciding on a framework. Since Django provides a lot of bells and whistles, you should take advantage of them. If you have strong disagreements with how Django handles something you may want to go with Flask. The same can be said if you won’t be taking advantage of the structure and tools that Django provides.
Let’s look at some examples.
If you’re application uses SQLite, PostgreSQL, MySQL, MariaDB, or Oracle, you should take a hard look at Django. On the other hand, if you’re using NoSQL or no database at all, then Flask is a solid choice.
Project Size and Anticipated Lifetime
Flask is better for smaller, less-complicated projects that have well-defined scopes and shorter anticipated lifetimes.
Since Django forces a consistent app structure regardless of the size of the project nearly all Django projects have a similar structure. Because of thus, Django better handles larger projects (with larger teams) that have longer lifetimes and potential for a lot of growth since you’ll most likely have to onboard new developers from time to time.
What kind of application are you building?
Django excels at creating full-featured web applications with server-side templating. If you’re just developing a static web site or RESTful web service that feeds your SPA or mobile application, Flask is a solid choice. Django coupled with Django REST Framework works well in the latter case too.
Designing a RESTful API?
Django REST Framework (DRF), one of the most popular third-party Django packages, is a framework used to expose Django models through a RESTful interface. It comes with everything you need (views, serializers, validation, auth) and more (browsable API, versioning, caching) for building APIs quickly and easily. That said, again, keep in mind that like the Django ORM it’s intended to be coupled with a relational database.
Flask has a number of great extensions as well:
Be sure to check out Connexion as well, which combines the view, serialization, and auth functionality into a single package!
Review this Stack Exchange answer for a number of other requirements you may want to take into account when choosing a framework.
Flask performs slightly better since it’s smaller and has fewer layers. The difference here is negligible though, especially when you take I/O into account.
So, which framework should you use? As always, it depends. The choice to go with one framework or language or tool over another depends almost entirely on the context and problem at hand.
Django is full-featured so it requires fewer decisions to be made by you or your team. You can probably move faster that way. However, if you disagree with one of the choices that Django makes for you or you have unique application requirements that limit the number of features you can take advantage of, you may want to look to Flask.
There’s always going to be tradeoffs and compromises.
Think about project constraints, like time, knowledge, and budget. What are some of your app’s key features? What can you not compromise on? Do you need to move quickly? Does your app require a great deal of flexibility? Try to put your opinions aside as you answer these questions.
In the end, both frameworks have lowered the barrier to entry for building web applications, making them much easier and quicker to develop.
I hope this has been helpful. For more, check out these two excellent resources: