Skip to main content

Generating and Customizing Responses

When you return a value from a view function, Flask must convert it into a response object that can be sent over HTTP. If you return a simple string, Flask automatically creates a response with that string as the body and a 200 OK status. However, you often need more control, such as setting custom headers, changing the status code, or returning JSON data.

Automatic Response Conversion

Flask uses the Flask.make_response() method in src/flask/app.py to transform view return values into Response objects. This method supports several types of return values:

  • Strings and Bytes: Converted into a response with the string/bytes as the body and a text/html mimetype.
  • Dictionaries and Lists: Automatically passed to jsonify() to create a JSON response.
  • Iterators/Generators: Used for streaming responses.
  • Tuples: A convenient way to define the body, status, and headers simultaneously.

If you return None from a view, Flask raises a TypeError, as every view must return a valid response.

Customizing with Tuples

The most common way to customize a response without creating a full object is to return a tuple. Flask expects the tuple to be in one of three formats:

  • (body, status)
  • (body, headers)
  • (body, status, headers)
@app.route("/api/resource", methods=["POST"])
def create_resource():
# Returns a body, a 201 Created status, and a custom header
return {"id": 123}, 201, {"X-Entity-ID": "123"}

Internally, Flask.make_response unpacks these tuples. If the second element is a dictionary or a list of pairs, Flask treats it as headers and assumes the status is 200. If it is an integer or string, it is treated as the status code.

The Response Object

The flask.wrappers.Response class is the default response object used by Flask. It inherits from Werkzeug’s Response but sets the default mimetype to text/html.

You can access and modify response attributes directly if you create the object yourself or use the make_response helper:

from flask import make_response

@app.route("/set-cookie")
def set_cookie():
resp = make_response("Cookie is set")
resp.set_cookie("theme", "dark")
resp.headers["X-Custom-Header"] = "Flask-Value"
return resp

Default Mimetype

Unlike Werkzeug's base response, which does not assume a mimetype, Flask's Response class explicitly sets it:

class Response(ResponseBase):
default_mimetype: str | None = "text/html"

This ensures that simple string returns are interpreted as HTML by browsers by default.

The Response object in Flask provides a max_cookie_size property that is synchronized with your application's configuration. In src/flask/wrappers.py, this property is defined to look up the MAX_COOKIE_SIZE key:

@property
def max_cookie_size(self) -> int:
if current_app:
return current_app.config["MAX_COOKIE_SIZE"]
return super().max_cookie_size

If a cookie exceeds this size (defaulting to 4093 bytes in Werkzeug), browsers may ignore it. You can adjust this by setting app.config["MAX_COOKIE_SIZE"].

Overriding the Response Class

If your application requires a different default behavior—for example, always defaulting to application/json or adding a standard header to every response—you can subclass Response and assign it to app.response_class.

from flask import Flask, Response

class MyResponse(Response):
default_mimetype = "application/xml"

app = Flask(__name__)
app.response_class = MyResponse

@app.route("/data")
def data():
# This will now have a Content-Type of application/xml
return "<data>Hello</data>"

When you set app.response_class, Flask.make_response will use your custom class whenever it needs to wrap a return value (like a string or dict) into a proper response object.