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/flaskand/external/second/flask- From complex routing./flaskand/second/flask- From multiple flask apps./lilya/flaskand/lilya/second/flask- From inside another Lilya
You will see the response:
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
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¶
- Routing for mounting composition using includes.
- Applications for app-level setup patterns.
- Troubleshooting for common path/mount issues.