Difficulty: Beginner
Building your first Flask application is a rewarding experience because Flask's simplicity lets you go from zero to a working web application in minutes. Let us walk through each piece of a basic Flask app to understand what every line does and how the framework processes requests.
The journey starts with importing Flask and creating an application instance. When you write 'app = Flask(__name__)', you create a Flask object that is the central registry for your application. The __name__ argument tells Flask where to find resources like templates and static files. If the module is the main script, __name__ is '__main__'. If it is an imported module, __name__ is the module's name. Flask uses this to resolve relative paths for the template and static folders.
Routes are the heart of any Flask application. A route maps a URL pattern to a Python function called a view function. You define routes using the @app.route() decorator. When Flask receives an HTTP request, it matches the URL against registered routes and calls the corresponding view function. The view function must return something Flask can convert into an HTTP response: a string, a tuple of (body, status_code, headers), a Response object, or a dictionary (which Flask automatically converts to JSON).
The debug mode is your best friend during development. When you run 'app.run(debug=True)' or set FLASK_DEBUG=1, Flask enables two powerful features. First, the automatic reloader watches your Python files for changes and restarts the server when you save a file, so you do not have to stop and restart manually. Second, the interactive debugger appears in your browser when an error occurs, showing a full stack trace with the ability to execute Python code at any frame. This debugger is a security risk in production, so never enable debug mode on a public server.
Flask's development server listens on 127.0.0.1:5000 by default. The address 127.0.0.1 means it only accepts connections from your own machine. To make it accessible from other devices on your network (useful for testing on your phone), pass host='0.0.0.0' to app.run(). The port defaults to 5000 but can be changed with the port parameter.
View functions can return various types. A plain string becomes an HTML response with a 200 status code. A tuple lets you customize the status code and headers. Returning a dict automatically creates a JSON response with the correct Content-Type header. For full control, you can create a Response object from the make_response() function.
Flask uses Python decorators extensively. If you are unfamiliar with decorators, they are functions that modify other functions. The @app.route('/') decorator registers the decorated function as a handler for the '/' URL. Under the hood, it calls app.add_url_rule('/', endpoint='hello', view_func=hello). Understanding this lets you register routes without decorators, which is useful for class-based views and testing.
The request-response cycle in Flask works as follows: a client sends an HTTP request, the WSGI server passes it to Flask, Flask creates a Request object and pushes an application context and request context, Flask matches the URL to a route and calls the view function, the view function returns a response, Flask converts it to a proper HTTP response, and the WSGI server sends it back to the client.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return '<h1>Welcome to My Flask App</h1>'
@app.route('/about')
def about():
return '<h1>About</h1><p>This is a Flask application.</p>'
@app.route('/greet/<name>')
def greet(name):
return f'<h1>Hello, {name}!</h1>'
if __name__ == '__main__':
app.run(debug=True, port=5000)
This app has three routes. The home route serves the root URL. The about route serves /about. The greet route uses a variable rule <name> to capture part of the URL as a function parameter. Debug mode enables auto-reloading and the interactive debugger.
from flask import Flask, jsonify, make_response
app = Flask(__name__)
# String response (HTML)
@app.route('/text')
def text_response():
return '<p>Plain HTML string</p>'
# Tuple response with status code
@app.route('/not-found')
def not_found():
return '<h1>Not Found</h1>', 404
# Dict response (auto JSON)
@app.route('/api/data')
def api_data():
return {'message': 'Hello', 'status': 'ok'}
# Explicit Response object
@app.route('/custom')
def custom_response():
resp = make_response('Custom response')
resp.headers['X-Custom-Header'] = 'MyValue'
return resp
Flask handles different return types intelligently. Strings become HTML, dicts become JSON, tuples let you set status codes, and make_response() gives you full control over headers and the response body.
# Instead of app.run(), use the flask CLI:
# Set the app (not needed if file is named app.py)
# export FLASK_APP=myapp.py
# Run in development mode
# flask run --debug
# Run on a different port
# flask run --port 8080
# Run accessible from network
# flask run --host 0.0.0.0
# List all routes
# flask routes
# Open a shell with app context
# flask shell
The flask CLI is the recommended way to run your app during development. It automatically finds app.py or wsgi.py, supports the --debug flag for hot reloading, and provides useful subcommands like 'routes' and 'shell'.
Routes, View Functions, Debug Mode, Development Server, Decorators