Skip to main content

Customizing JSON Behavior

Flask uses a provider-based system for JSON operations, allowing you to customize how data is serialized and deserialized. By default, Flask uses the DefaultJSONProvider, which wraps Python's built-in json library and adds support for common types like datetime, UUID, and dataclasses.

Basic Customization

You can modify the behavior of the default JSON provider by changing attributes on the app.json instance. This is useful for adjusting formatting or sorting without creating a new class.

from flask import Flask

app = Flask(__name__)

# Disable ASCII escaping to support non-ASCII characters in output
app.json.ensure_ascii = False

# Disable key sorting for better performance
app.json.sort_keys = False

# Force compact output even in debug mode
app.json.compact = True

The DefaultJSONProvider supports the following configuration attributes:

  • ensure_ascii: If True (default), non-ASCII characters are escaped.
  • sort_keys: If True (default), dictionary keys are sorted alphabetically.
  • compact: If True, output has no indentation or extra spaces. If None (default), it is compact unless the app is in debug mode.
  • mimetype: The mimetype used by jsonify (default is "application/json").

Supporting Custom Types

To support serializing custom objects, you can override the default method of the provider. This method is called for any object that the standard JSON library cannot handle.

from flask import Flask
from flask.json.provider import DefaultJSONProvider

class MyUser:
def __init__(self, name):
self.name = name

class CustomJSONProvider(DefaultJSONProvider):
@staticmethod
def default(obj):
if isinstance(obj, MyUser):
return {"_type": "User", "name": obj.name}
return super(CustomJSONProvider, CustomJSONProvider).default(obj)

app = Flask(__name__)
app.json = CustomJSONProvider(app)

Note that DefaultJSONProvider.default already handles datetime (as RFC 822 strings), UUID, dataclasses, and objects with an __html__ method.

Using Alternative JSON Libraries

If you need to use a faster library like orjson or ujson, you can implement a custom JSONProvider. You must implement at least the dumps and loads methods.

import orjson
from flask import Flask
from flask.json.provider import JSONProvider

class OrjsonProvider(JSONProvider):
def dumps(self, obj, **kwargs):
# orjson.dumps returns bytes, Flask expects a string
return orjson.dumps(obj, **kwargs).decode()

def loads(self, s, **kwargs):
return orjson.loads(s, **kwargs)

app = Flask(__name__)
app.json = OrjsonProvider(app)

When implementing a custom provider, remember that JSONProvider requires an application instance during initialization to maintain a weak reference to the app.

Customizing JSON Loading

You can also customize how JSON is loaded, for example, by providing an object_hook to the underlying json.loads call. This is done by overriding the loads method in a subclass of DefaultJSONProvider.

from flask import Flask
from flask.json.provider import DefaultJSONProvider

class HookProvider(DefaultJSONProvider):
def object_hook(self, obj):
if "_type" in obj and obj["_type"] == "User":
return MyUser(obj["name"])
return obj

def loads(self, s, **kwargs):
kwargs.setdefault("object_hook", self.object_hook)
return super().loads(s, **kwargs)

app = Flask(__name__)
app.json = HookProvider(app)

Registering the Provider

There are two ways to register a custom JSON provider in Flask:

  1. Assigning to app.json: Create an instance of your provider and assign it to the json attribute of an existing Flask app.

    app.json = CustomProvider(app)
  2. Setting json_provider_class: Subclass Flask and set the json_provider_class attribute. Flask will automatically instantiate it.

    class MyFlask(Flask):
    json_provider_class = CustomProvider

    app = MyFlask(__name__)

Troubleshooting

jsonify Arguments

The jsonify function (and the underlying app.json.response method) accepts either positional arguments or keyword arguments, but not both. Passing both will raise a TypeError.

# Valid: positional args (serialized as a list)
jsonify(1, 2, 3)

# Valid: keyword args (serialized as a dict)
jsonify(id=1, name="Flask")

# Invalid: raises TypeError
jsonify(1, 2, name="Flask")

Trailing Newlines

The DefaultJSONProvider.response method adds a trailing newline to the JSON output. This is a standard practice for many HTTP clients and command-line tools like curl. If you implement a custom response method in a JSONProvider subclass, you should decide whether to maintain this behavior.

Key Sorting Requirements

When app.json.sort_keys is enabled (which is the default), all keys in dictionaries must be strings. The json library does not convert keys to strings before sorting, so including non-string keys will result in a TypeError during serialization.