Skip to content

WSGI frameworks

Did you know because of the awesome work from a2wsgi you can integrate any wsgi framework (Flask, Django...)?

Yes, that's right, you can now smoothly move to Lilya without rewriting your old applications from the scratch, actually, you can reuse them directly within Lilya, even another Lilya running inside another Lilya, a Lilyaception.

WSGIMiddleware

Using this middleware is very simple, let's use Flask as example since it is very fast to spin-up a Flask service compared to other giants like Django.

You can mount WSGI applications in multiple ways:

  • directly in routes using Include(..., app=WSGIMiddleware(...))
  • behind nested includes
  • side-by-side with native Lilya routes

Why this exists

This is mostly useful when:

  • migrating incrementally from WSGI to ASGI;
  • keeping legacy admin/billing modules while new APIs are built in Lilya;
  • reusing existing Flask/Django WSGI apps under selected prefixes.

Important behavior

  • WSGI apps run in a sync model under the adapter.
  • Lilya routes still run as native ASGI handlers.
  • Prefix mapping decides which requests hit WSGI vs Lilya handlers.

Note

Keep path boundaries explicit when mixing WSGI and Lilya. Prefix collisions are usually the main source of confusion.

from flask import Flask, request

from lilya.apps import Lilya
from lilya.middleware.wsgi import WSGIMiddleware
from lilya.requests import Request
from lilya.routing import Include, Path

flask_app = Flask(__name__)


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


async def home(request: Request):
    name = request.path_params["name"]
    return {"name": name}


app = Lilya(
    routes=[
        Path("/home/{name:str}", handler=home),
        Include("/flask", WSGIMiddleware(flask_app)),
    ]
)
from flask import Flask, request

from lilya.apps import Lilya
from lilya.middleware.wsgi import WSGIMiddleware
from lilya.requests import Request
from lilya.routing import Include, Path

flask_app = Flask(__name__)


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


async def home(request: Request):
    name = request.path_params["name"]
    return {"name": name}


app = Lilya(
    routes=[
        Path("/home/{name:str}", handler=home),
        Include(
            "/",
            routes=[
                Include("/flask", WSGIMiddleware(flask_app)),
            ],
        ),
    ]
)
from flask import Flask, request

from lilya.apps import Lilya
from lilya.middleware.wsgi import WSGIMiddleware
from lilya.requests import Request
from lilya.routing import Include, Path

flask_app = Flask(__name__)
second_flask_app = Flask(__name__)


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


@second_flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


async def home(request: Request):
    name = request.path_params["name"]
    return {"name": name}


routes = [
    Path("/home/{name:str}", handler=home),
    Include(
        "/",
        routes=[
            Include(
                "/internal",
                routes=[
                    Include(
                        routes=[
                            Include("/flask", WSGIMiddleware(flask_app)),
                        ]
                    )
                ],
            ),
            Include(
                "/",
                routes=[
                    Include(
                        "/",
                        routes=[
                            Include(
                                "/external",
                                routes=[
                                    Include(
                                        "/second/flask",
                                        WSGIMiddleware(second_flask_app),
                                    ),
                                ],
                            )
                        ],
                    )
                ],
            ),
        ],
    ),
]

app = Lilya(routes=routes)
from flask import Flask, request

from lilya.apps import Lilya
from lilya.middleware.wsgi import WSGIMiddleware
from lilya.requests import Request
from lilya.routing import Include, Path

flask_app = Flask(__name__)
second_flask_app = Flask(__name__)


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


async def home(request: Request):
    name = request.path_params["name"]
    return {"name": name}


@second_flask_app.route("/")
def second_flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from Flask!"


routes = [
    Include(
        path="/",
        routes=[
            Path("/home/{name:str}", handler=home),
            Include("/flask", WSGIMiddleware(flask_app)),
            Include("/second/flask", WSGIMiddleware(second_flask_app)),
        ],
    )
]

app = Lilya(routes=routes)
from flask import Flask, request

from lilya.apps import Lilya
from lilya.middleware.wsgi import WSGIMiddleware
from lilya.requests import Request
from lilya.routing import Include, Path

flask_app = Flask(__name__)
second_flask_app = Flask(__name__)


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


async def home(request: Request):
    name = request.path_params["name"]
    return {"name": name}


@second_flask_app.route("/")
def second_flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from Flask!"


sub_lilya = Lilya(
    routes=[
        Path("/home/{name:str}", handler=home),
        Include("/flask", WSGIMiddleware(flask_app)),
        Include("/second/flask", WSGIMiddleware(second_flask_app)),
    ]
)

routes = [Include("/sub-lilya", app=sub_lilya)]

app = Lilya(routes=routes)
from flask import Flask, request

from lilya.apps import ChildLilya, Lilya
from lilya.middleware.wsgi import WSGIMiddleware
from lilya.requests import Request
from lilya.routing import Include, Path

flask_app = Flask(__name__)
second_flask_app = Flask(__name__)


@flask_app.route("/")
def flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from your Flask integrated!"


async def home(request: Request):
    name = request.path_params["name"]
    return {"name": name}


@second_flask_app.route("/")
def second_flask_main():
    name = request.args.get("name", "Lilya")
    return f"Hello, {name} from Flask!"


child_lilya = ChildLilya(
    routes=[
        Path("/home/{name:str}", handler=home),
        Include("/flask", WSGIMiddleware(flask_app)),
        Include("/second/flask", WSGIMiddleware(second_flask_app)),
    ]
)

routes = [Include("/child-lilya", app=child_lilya)]

app = Lilya(routes=routes)

You already get the idea, the integrations are endless!

Check it

With all of examples from before, you can now verify that the integrations are working.

The paths pointing to the WSGIMiddleware will be handled by Flask and the rest is handled by Lilya, including the Lilya inside another Lilya.

If you run the endpoint handled by Flask:

  • /flask - From simple routing.
  • /flask - From nested routing.
  • /internal/flask and /external/second/flask - From complex routing.
  • /flask and /second/flask - From multiple flask apps.
  • /lilya/flask and /lilya/second/flask - From inside another Lilya

You will see the response:

Hello, Lilya from Flask!

Accessing any Lilya endpoint:

  • /home/lilya - From simple routing.
  • /home/lilya - From complex routing.
  • /home/lilya - From nested routing.
  • /home/lilya - From multiple flask apps.
  • /lilya/home/lilya - From inside another Lilya
{
    "name": "lilya"
}

Production notes

  • Prefer clear mount prefixes (/legacy, /admin, etc.) over overlapping paths.
  • Keep heavy async workloads in native ASGI routes when possible.
  • Add request logging to verify traffic distribution between WSGI and Lilya branches.

See also