- 👤 Andrés Cruz
The Master Guide to Flask: Web Development with Python from Start to Finish
In the vast universe of Python web development, Flask shines as a beacon of flexibility and power. Unlike larger, more "opinionated" frameworks, Flask is a microframework that gives you total control, providing a solid, minimalist core upon which you can build anything, from a simple blog to a complex RESTful API or a real-time application. At DesarrolloLibre, we've explored every facet of Flask, and this guide is the distillation of years of practical experience.
This SUPER post is a complete manual that will walk you through every stage of the Flask development lifecycle. We'll start with setting up your environment and your first "Hello, World" application. Then, we'll delve into the framework's pillars: routing, the Jinja2 templating engine, configuration management, and environment variables. We will build a robust application with database handling, user authentication, role-based access control, secure forms, and flash notifications. Finally, we'll explore the advanced Flask ecosystem with asynchronous tasks, WebSockets, caching, testing, and show you how to deploy your creation to the cloud.
Get ready to master Flask, a tool that embodies the simplicity and power of Python.
Flask is a great web framework for creating server-side web applications with Python; If you do not have knowledge of using server web frameworks with Python, Flask is a good candidate to start with; Being a microframework, which means that initially it comes with the minimum necessary to be able to function, you can see little by little how the framework works without giving rise to confusion with files, directory structure or modules that you have not placed, as happens with others. more robust frameworks like Django, which when creating a project in Django, has many files and folders.
Although Flask is a microframework does not mean that it should be used for small projects, since it has a large number of extensions that you can configure for the project based on its needs; for example, if you need to send emails, there are already extensions, as well as if you want to log in socially, connect via ftp, user modules, etc.
Flask is a microframework used for the development of web applications in Python, although the term microframework does not confuse you since you can use it to build all kinds of web applications, both small and large. Some of its main features are:
Flask main features
Flask is a great microframework to start developing web applications with Python. Being a microframework, it provides the bare minimum to work without worrying about a structure that is difficult for beginners to follow, as is the case with Django, which makes it an excellent candidate to start with. in this little world.
Among the main features of Flask we have:
- Perfect for developing basic applications that you may want to scale in the future.
- It includes a development server, therefore, we can quickly start developing applications.
- Includes several packages for unit testing.
- It is compatible with WSGI with which we can easily serve our application.
- It uses Python, so we have the entire Python ecosystem at our disposal.
- Its learning curve is quite low if we compare it with other frameworks.
- It is extensible through extensions or plugins created specifically for Flask.
- The minimum to work, Flask is a framework with a fairly low learning curve, being a microframework and bringing the minimum to be able to work, it is quite easy to understand, create our first hello world and scale little by little.
- Age, Flask is a framework that has been on the market for a long time, it is constantly receiving updates to use the latest versions of Python and dependencies in general and incorporate new features.
- Extensions, Flask offers a wide variety of extensions that allow you to add additional functionalities, such as form validation, integration with databases, template engine, among others.
- Community support and good documentation, when you have a question about how to implement some functionality, with a simple search, you will surely be able to find more information about how to
- implement said functionality, having an active community and very good documentation.
These are just some of the main features of Flask, but there are many others.
When installing Flask, several dependencies are installed, among the main ones we have:
- Flask, the microframework known as Flask.
- Jinja2, an excellent templating engine for creating dynamic HTML pages with the help of Python.
- Werkzeug, WSGI (Web Server Gateway Interface) type server used to present the application and be able to consume it through the web browser or similar; It is also used to manage routing, handle HTTP requests and responses, among others.
Section 1: Fundamentals and Initial Setup
Before we can build complex applications, we must lay a solid foundation. This section will guide you through the installation of Flask, configuring your development environment in Visual Studio Code, and understanding essential concepts like environment variables and configuration files, which are crucial for creating maintainable and secure applications.
Preparing the Environment for Flask Development
If you're taking your first steps in Python web development, Flask is the perfect starting point. Its microframework nature makes it lightweight, flexible, and extremely powerful.
What is Flask?
Flask is a microframework for Python based on Werkzeug (a WSGI utility library) and Jinja2 (a templating engine). The term "micro" doesn't mean it's limited; it means its core is small and doesn't impose decisions on which tools to use. It gives you the freedom to choose your own libraries for database access (ORM), form validation, etc.
In my experience, this flexibility is its greatest strength. Unlike monolithic frameworks, Flask allows you to build the application piece by piece, understanding every component you add.
Installation and Virtual Environment
The first rule of Python development is: always use a virtual environment. This isolates your project's dependencies and avoids conflicts.
# 1. Create and navigate to your project folder
mkdir my-flask-app && cd my-flask-app
# 2. Create a virtual environment
python -m venv venv
# 3. Activate the virtual environment
# Windows
.\venv\Scripts\activate
# macOS/Linux source venv/bin/activate
# 4. Install Flask
pip install FlaskConfiguration in Visual Studio Code
VS Code is an excellent editor for Flask development. For an optimal experience:
- Install the official Python extension from Microsoft.
- Select your virtual environment's interpreter: Press Ctrl+Shift+P, search for "Python: Select Interpreter," and choose the one inside your venv folder.
With this, your environment is ready for the linter, debugger, and autocompletion to work correctly with your project's dependencies.
Follow the complete setup guide at: Prepare the environment to start developing our applications in Flask.
"Hello World" in Flask: Your First Web Application
Once the environment is configured, creating a functional web application in Flask requires only a few lines of code.
Creating the Main File
Create a file, for example run.py, with the following content:
from flask import Flask
# 1. Create an instance of the Flask application
# __name__ le dice a Flask dónde buscar recursos como plantillas y archivos estáticos.
app = Flask(__name__)
# 2. Define a route using a decorator
# This links the root URL ("/") to the home()
@app.route('/')
def home():
# 3. The view function returns the response that will be sent to the browser.
return "¡Hola, Mundo desde Flask!"
# 4. (Optional, for development) Start the server if the script is run directly.
if __name__ == '__main__':
app.run(debug=True)Running the Application
You can run the application in two ways:
- Directly with Python: python run.py. The if __name__ == '__main__': will take care of starting the server.
- With the flask command: First, you need to tell Flask where your application is via environment variables, and then you can use the flask run command.
The debug=True mode is incredibly useful during development, as it automatically restarts the server with every change and provides an interactive debugger in the browser if an error occurs.
Create your first app in minutes with our guide: Hello World Flask: create your first web app with Python.
Environment Variables: .flaskenv
Environment variables are crucial for configuring Flask's behavior without modifying the code. The two most important ones are:
- FLASK_APP: Tells the flask command which file or module contains your application.
- FLASK_ENV (or FLASK_DEBUG in newer versions): Defines the environment. If set to development, it activates debug mode.
Instead of setting them manually in the terminal every time, Flask can load them automatically from .env or .flaskenv files if you have python-dotenv installed.
$ pip install python-dotenvNow, create a file named .flaskenv in your project's root:
# .flaskenv
$ FLASK_APP=run.py
$ FLASK_ENV=developmentWith this file, you only need to run flask run in your terminal, and Flask will know what to do. For sensitive variables (like API keys), use a .env file, which is also loaded automatically but should not be uploaded to your Git repository.
Master environment variables in: Create environment variables in Flask .flaskenv.
Configuration Files for a Scalable App
As your application grows, you'll need to manage more configuration parameters: the secret key, the database URI, mail settings, etc. Flask allows you to load configurations from an object, a class, or a file.
A recommended practice is to create a config.py file with different classes for each environment:
# config.py
class Config:
SECRET_KEY = 'una-clave-secreta-muy-segura'
class DevConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
class ProdConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'postgresql://user:pass@host/db'Then, in your application's main file, you can load the desired configuration:
from flask import Flask
import config
app = Flask(__name__)
app.config.from_object(config.DevConfig) # Load the development configurationThis allows you to easily switch between configurations for development, testing, and production without touching the application code. The SECRET_KEY is especially important, as Flask and its extensions use it to cryptographically sign session cookies and other security data.
Learn to structure your configurations in: Managing configuration parameters in Flask.
Section 2: Building the Web Application
With the fundamentals in place, it's time to build the main features of our web application. This section covers Flask's routing system to define our application's URLs, the use of the Jinja2 templating engine for rendering dynamic HTML, and handling web forms safely and efficiently with the WTForms extension.
Routes and Views: The Heart of a Flask Application
In Flask, a "route" is the association between a URL and a Python "view function." The @app.route() decorator is responsible for creating this association.
Dynamic Routes
Often, a URL needs to accept a variable part. For example, to display a product's profile by its ID. Flask handles this elegantly by specifying the variable type in the route.
@app.route('/producto/<int:id>')
def ver_producto(id):
# The 'id' variable has already been converted to an integer. return f"Displaying product with ID: {id}"
# Here we would look up the product in the database with that id.
return f"Mostrando el producto con ID: {id}"You can use converters like string (default), int, float, and path.
HTTP Methods
By default, a route only responds to GET requests. To handle other methods like POST (for submitting forms), you must specify them in the decorator.
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# Process the login form data
return "Procesando login..."
else:
# Display the login form
return "This is the login form."In Flask 2.0 and later, you can use more readable shortcut decorators: @app.get('/path') and @app.post('/path').
Master the routing system in: Routes in Flask.
Templating Engine with Jinja2
You'll rarely want to return plain text. Flask integrates with the Jinja2 templating engine to render dynamic HTML.
To use it, you need a folder named templates in the root of your project. The render_template() function will look for HTML files there.
@app.route('/saludo/<string:nombre>')
def saludo(nombre):
# We pass the 'name' variable to the template context.
return render_template('saludo.html', nombre=nombre)Inside templates/greeting.html, you can use Jinja2 syntax:
<h1>Hello, {{ name }}!</h1>Control Structures and Template Inheritance
Jinja2 is a complete templating engine. It supports loops, conditionals, and, most importantly, template inheritance. This allows you to create a base template (base.html) with the common structure (head, navbar, footer) and have other templates extend it.
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>Additionally, you can create macros to generate reusable HTML fragments, such as a pagination component.
Learn everything about Jinja2 in: Jinja2 in Flask 3 and create a pagination macro.
Secure and Validated Forms with WTForms
Handling HTML forms directly is tedious and error-prone. The Flask-WTF extension integrates with the WTForms library to provide a high-level solution for:
- Rendering form fields.
- Validating user-submitted data on the server side.
- Protecting against Cross-Site Request Forgery (CSRF) attacks.
The process involves defining a form class that inherits from FlaskForm.
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Log in')In your view function, you create an instance of the form and handle the validation.
@app.route('/login', methods=['GET', 'POST'])
def login():
# 1. Instantiate the form object
form = LoginForm()
# 2. Handle form submission (POST request) and validation
if form.validate_on_submit():
# The data is valid. Process the login.
# form.email.data and form.password.data contain the submitted values.
# Display a success message (flash message)
flash(f'Login requested for user {form.email.data}')
# Redirect the user to the home page (Post/Redirect/Get pattern)
return redirect(url_for('home'))
# 3. Handle initial page load (GET) or validation failure (POST)
# Render the login template and pass the form object to it.
return render_template('login.html', form=form)In the template, you can render the fields, including labels and error messages. Flask-WTF also takes care of adding a hidden CSRF token for security.
Build robust forms with: WTForms in Flask 3.
Section 3: Authentication and User Management
Almost all web applications need a way to identify their users. This section will guide you through implementing a complete authentication and authorization system in Flask, from managing session data and user authentication to creating a role-based access control system.
Session in Flask: Storing User Data
HTTP is a stateless protocol, meaning each request is independent. To remember who a user is between requests, we need a session mechanism. Flask provides a session object that works like a dictionary. You can store data in it, and it will be available in subsequent requests from the same user.
By default, Flask uses secure cookies (cryptographically signed) to store session data on the client side. That's why it's crucial to set a strong SECRET_KEY in your configuration.
from flask import session, redirect, url_for
@app.route('/set_user/<name>')
def set_user(name):
# Store the 'name' captured from the URL route into the session dictionary
session['username'] = name
return 'User saved to session.'The session is the foundation upon which we will build our authentication system.
Understand how the session works in: Session in Flask: how to store and manage user data.
User Authentication with Flask-Login
The Flask-Login extension greatly simplifies user session management. It handles logging users in and out, remembering users between sessions, and protecting views so that only authenticated users can access them.
Flask-Login Setup
The process requires several steps:
- Initialize the extension: login_manager = LoginManager(app)
- Create a User Model: Your user model (e.g., from SQLAlchemy) must inherit from UserMixin, which provides the default implementations that Flask-Login needs.
- Create a user_loader: You must provide a function decorated with @login_manager.user_loader that tells Flask-Login how to load a user from their ID, which is stored in the session.
from flask_login import UserMixin, login_user, logout_user, login_required, current_user class User(UserMixin, db.Model): # ... your fields ... @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id))Logging In and Out
In your login view, after validating the user's credentials, you call login_user().
from flask_login import UserMixin, login_user, logout_user, login_required, current_user
class User(UserMixin, db.Model):
# ... fields ...
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))To log out, you simply call logout_user().
View Protection and current_user
To protect a route, you just need to add the @login_required decorator. If an unauthenticated user tries to access it, Flask-Login will redirect them to the login page.
Inside any view, you can access the currently authenticated user through the current_user proxy.
from flask_login import login_required, current_user @app.route('/dashboard') @login_required def dashboard(): return f"Welcome to your dashboard, {current_user.username}!"Implement a complete login system with: How to implement user authentication with Flask-Login.
Role-Based Access Control (RBAC)
Authentication answers the question "who are you?", while authorization answers "what are you allowed to do?". A role system is the most common way to implement authorization.
The process involves extending your database to include Role models and an association table to handle a many-to-many relationship between users and roles.
@app.route('/login', methods=['GET', 'POST'])
def login():
# ... validations ...
user = User.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember_me.data)
return redirect(url_for('dashboard'))
# ...Creating a Permission Decorator
To protect routes for specific roles (e.g., 'admin'), we can create our own decorator.
from functools import wraps
from flask import abort
def role_required(role_name):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated or not current_user.has_role(role_name):
abort(403) # Forbidden
return f(*args, **kwargs)
return decorated_function
return decorator
@app.route('/admin')
@login_required
@role_required('admin')
def admin_dashboard():
return "Welcome to the administrator panel."This system gives you granular control over who can access which parts of your application.
Add a role and permissions system with: How to implement Role-Based Access Control in Flask.
Section 4: Advanced Topics and Flask Ecosystem
Once you master the fundamentals, the Flask ecosystem opens up a world of possibilities for building more powerful, interactive, and efficient applications. In this section, we'll explore how to create RESTful APIs, enable real-time communication with WebSockets, optimize performance with background tasks and caching, and ensure your code quality with automated tests.
Creating RESTful APIs
Flask is an exceptional tool for building RESTful APIs thanks to its simplicity. A REST API allows different systems (like a mobile application or a JavaScript frontend) to communicate with your backend via HTTP.
The principle is the same as with web views, but instead of returning HTML with render_template, you return data in JSON format using the jsonify function.
from flask import jsonify
@app.route('/api/tasks', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
return jsonify([task.to_dict() for task in tasks])
@app.route('/api/tasks', methods=['POST'])
def create_task():
# ... lógica para crear la tarea a partir de request.json ...
return jsonify(new_task.to_dict()), 201 # 201 CreatedEnabling CORS for Your API
If your API will be consumed by a frontend that lives on a different domain, you'll encounter CORS (Cross-Origin Resource Sharing) errors. For security reasons, the browser blocks these requests. The Flask-CORS extension solves this by adding the necessary HTTP headers.
$ pip install Flask-Corsfrom flask_cors import CORS
app = Flask(__name__)
# Enable CORS for all routes and origins CORS(app)
CORS(app) For production, you can configure it to allow only specific origins.
Build your first API in: Create a Restful API in Flask and enable CORS.
Asynchronous Background Tasks with Celery
Some tasks take too long to run within an HTTP request, such as sending an email, processing an image, or generating a report. If you do it in the view, the user will have to wait until the task finishes, resulting in a poor experience.
Celery is a distributed task queue that allows you to execute these tasks asynchronously in a separate process ("worker").
The flow is:
- A Flask view receives a request.
- Instead of executing the heavy task directly, it "sends" it to the Celery queue with .delay().
- The view returns an immediate response to the user.
- A Celery "worker" process, running in the background, picks up the task from the queue and executes it.
This is indispensable for the scalability and responsiveness of your application.
Real-Time Communication with Flask-SocketIO
For applications that require instant, bidirectional communication, such as chats or real-time notifications, the HTTP request-response model is not enough. This is where WebSockets come in.
The Flask-SocketIO extension integrates the Socket.IO protocol into your Flask application, allowing persistent, full-duplex communication between the client and the server.
You can define "events" and "rooms" to send messages to specific clients.
from flask_socketio import SocketIO, emit, join_room
app = Flask(__name__)
socketio = SocketIO(app)
@socketio.on('join')
def on_join(data):
room = data['room']
join_room(room)
emit('status', {'msg': 'Joined.'}, to=room)
@socketio.on('chat_message')
def handle_message(data):
room = data['room']
emit('new_message', data['message'], to=room)This allows you to build highly interactive applications without the client having to constantly "poll" the server for new data.
Create your first real-time application with: How to use Flask-SocketIO.
Unit Testing with Pytest
Writing automated tests is a fundamental practice to ensure your application works correctly and to prevent regressions. Pytest is a testing framework for Python that makes writing tests simple and readable.
Flask integrates well with Pytest. You can create a "fixture" to set up a test client that makes requests to your application without the need for a real web server.
# tests/conftest.py
import pytest
from my_app import create_app
@pytest.fixture
def client():
# 1. Create a Flask application instance configured for testing
app = create_app('testing')
# 2. Use the application's test client for making requests
with app.test_client() as client:
# 3. Establish an application context
with app.app_context():
# Here you could initialize the test database (e.g., db.create_all())
pass
# 4. Yield the client for the test function to use
yield clientTests give you the confidence to refactor and add new features without fear of breaking what already works.
Learn to configure your test suite in: Unit Tests in Flask with Pytest.
Section 5: Deployment
Once your application is built and tested, the final step is to put it online for the world to use. Deployment can seem intimidating, but modern platforms like Railway have greatly simplified it, allowing you to go from code on your machine to a live application in a matter of minutes.
Deploying a Flask Project on Railway
Railway is a cloud infrastructure platform that automates much of the deployment process. It works by connecting to your GitHub repository and deploying your application every time you push to your main branch.
Preparing the Project for Deployment
Before deploying, you need three key files in your repository:
- requirements.txt: A list of all your project's Python dependencies. Generated with pip freeze > requirements.txt. Railway will use it to install everything needed.
- Procfile: A text file without an extension that tells Railway how to run your application. For a Flask application, you need a production WSGI server like Gunicorn.
# Procfile web: gunicorn --bind 0.0.0.0:$PORT run:app(Make sure you have gunicorn in your requirements.txt).
- runtime.txt (Optional but recommended): Specifies the Python version to use.
# runtime.txt python-3.11.4Railway Deployment Process
- Create an account on Railway and connect your GitHub.
- Create a New Project: Select "Deploy from GitHub repo" and choose your Flask repository.
- Provision a Database: If your application needs a database, you can add a PostgreSQL or MySQL service with a single click from the Railway panel.
- Configure Environment Variables: Railway will detect your database variables and inject them into your application. You must manually add any other variables you need, such as your SECRET_KEY or third-party API keys.
- Deploy! Railway will detect your Procfile and requirements.txt, build your application, and deploy it. In minutes, it will provide you with a public URL where your application will be live.
Platforms like Railway democratize deployment, allowing developers to focus on code and not on the complexity of infrastructure.
Follow our step-by-step guide to deploy your application in: Deploy a Flask or FastAPI project on Railway.
Course and Book to Master Flask 3
Remember that on this blog, you have access to COMPLETE courses and books to help you master Flask. All the posts mentioned above are taken from the course and book; you can purchase them from the Courses and Books section in the menu.
Conclusion: The Power of Flask's Simplicity
Throughout this guide, we have journeyed from the most basic concepts of Flask to the construction and deployment of a complete and robust web application. We have seen how Flask's microframework philosophy, far from being a limitation, is its greatest strength. It grants you the freedom to choose your tools, structure your project as you wish, and build exactly the application you need, without the burden of unnecessary components.