Back to Sanic

Version 25.12 (LTS)

guide/content/en/release-notes/2025/v25.12.md

25.12.05.4 KB
Original Source

Version 25.12 (LTS)

.. toc::

Introduction

Version 25.12 is the Long Term Support (LTS) release for the version 25 release cycle. As an LTS release, it will receive security updates and critical bug fixes for an extended period. If you run into any issues, please raise a concern on GitHub.

What to know

More details in the Changelog. Notable new or breaking features, and what to upgrade:

Python 3.9 removed, Python 3.14 added

Sanic now requires Python 3.10 or newer. Python 3.9 has been dropped, and Python 3.14 support has been added.

Daemon mode

You can now run Sanic as a background daemon process directly from the CLI.

sh
sanic path.to.app -D
sanic path.to.app --daemon

This also introduces convenience commands for managing daemon processes:

sh
sanic path.to.app status    # Check if running
sanic path.to.app stop      # Stop the daemon

Additional options are available:

sh
--pidfile PATH    # Custom PID file location
--logfile PATH    # Log output to file
--user USER       # Run as specified user
--group GROUP     # Run as specified group

Lower-level commands are also available:

sh
sanic kill --pid=<PID>
sanic kill --pidfile=<PATH>
sanic status --pid=<PID>
sanic status --pidfile=<PATH>

Sanic now provides granular control over symlinks in static file serving with two new parameters:

ParameterDefaultDescription
follow_external_symlink_filesFalseAllow serving file symlinks that point outside the static root
follow_external_symlink_dirsFalseAllow serving files from directory symlinks that point outside the static root

Examples

Secure defaults (block external symlinks):

python
# Symlinks pointing outside /var/www/static will return 404
app.static("/static", "/var/www/static")

Allow file symlinks only:

python
# Serves /var/www/static/config.json -> /etc/app/config.json
app.static("/static", "/var/www/static", follow_external_symlink_files=True)

Allow directory symlinks only:

python
# Serves files from /var/www/static/images/ -> /shared/images/
app.static("/static", "/var/www/static", follow_external_symlink_dirs=True)

Custom configuration converters

You can now extend how Sanic parses environment variables into configuration values. By default, Sanic converts environment variables using str, str_to_bool, float, and int converters (tried in reverse order). You can add your own converters to handle custom types.

Simple converter - a callable that takes a string and returns a converted value:

python
class UltimateAnswer:
    def __init__(self, answer):
        self.answer = int(answer)

config = Config(converters=[UltimateAnswer])
app = Sanic("MyApp", config=config)

# Or register after creation
app.config.register_type(UltimateAnswer)

DetailedConverter - for converters that need more context (full key name, config key, value, and defaults):

python
from sanic.config import Config, DetailedConverter

class TypeAwareConverter(DetailedConverter):
    def __call__(self, full_key: str, config_key: str, value: str, defaults: dict):
        if config_key in defaults:
            # Cast to the same type as the default value
            return type(defaults[config_key])(value)
        raise ValueError  # Fall through to next converter

config = Config(
    defaults={"PORT": 8000, "DEBUG": False},
    converters=[TypeAwareConverter()]
)

Automatic charset for text content types

Text content types (text/*) now automatically include charset=UTF-8 when serving static files and file responses.

Task creation returns the task

When creating a task via app.add_task(), the asyncio Task object is now returned, allowing you to await or check its result later.

python
task = app.add_task(some_coroutine())
# Later...
result = await task

Improved CLI error messages

Tracerite has been upgraded to v2.2.0, providing better formatted exception tracebacks in the CLI with improved chained exception display.

Thank you

Thank you to everyone that participated in this release: :clap:

@ahopkins @amarquard089 @ChihweiLHBird @dhensen @dungarpan @gazpachoking @helioascorreia @jameslovespancakes @Peopl3s @tdaron @tiejunhu @tkosman @Tronic @wojonet


If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: financial contributions.