Tornado Framework — Core Concepts
What Tornado is
Tornado is a Python web framework and asynchronous networking library originally developed at FriendFeed in 2009. It was open-sourced after Facebook acquired FriendFeed, and it has been maintained continuously since then.
What distinguishes Tornado from other Python web frameworks is its integrated networking stack. Tornado includes its own event loop (called the IOLoop), its own HTTP server, and its own HTTP client. This was necessary because when Tornado was created, Python had no standard async infrastructure — asyncio didn’t exist until Python 3.4 (2014).
The event loop model
At Tornado’s heart is the IOLoop — an event loop that monitors file descriptors (network sockets, pipes) for readiness. When data arrives on a socket, the IOLoop calls the registered handler. When a socket is ready to send data, the IOLoop lets the handler write.
This is fundamentally different from the thread-per-request model:
Thread-per-request: Each connection gets a thread. 10,000 connections = 10,000 threads. Each thread costs memory (~8MB stack) and switching between threads costs CPU time. This model breaks down around a few thousand connections.
Event-driven (Tornado): One thread monitors all connections. When any connection needs attention, a handler runs briefly, then control returns to the loop. 10,000 connections = one thread, a few MB of memory.
This is often called the C10K problem — how to handle 10,000 concurrent connections. Tornado was designed explicitly to solve it in Python.
Core components
RequestHandler is the base class for handling HTTP requests. Each handler defines methods for HTTP verbs:
class UserHandler(tornado.web.RequestHandler):
async def get(self, user_id):
user = await db.get_user(user_id)
self.write({"name": user.name})
async def post(self):
data = tornado.escape.json_decode(self.request.body)
await db.create_user(data)
self.set_status(201)
Application maps URL patterns to handlers using regex (unlike the path-based routing in newer frameworks).
WebSocketHandler provides built-in WebSocket support — one of Tornado’s original selling points.
AsyncHTTPClient is a non-blocking HTTP client for making requests to external services without blocking the event loop.
Long polling and WebSockets
Tornado was built for real-time features before WebSockets were widely supported. It pioneered long polling in Python — a technique where the client sends a request, the server holds it open until there’s new data, then responds and the client immediately reconnects.
Once WebSockets became standard, Tornado added native support. A WebSocket connection in Tornado stays open, and the server can push messages to the client at any time. This is essential for chat applications, live dashboards, collaborative editing, and gaming.
The asyncio integration
When Python 3.4 introduced asyncio, Tornado faced a decision: replace its IOLoop or integrate with it. Tornado chose integration. Since Tornado 5.0, the IOLoop is a wrapper around asyncio’s event loop. This means:
- You can use
asynciolibraries inside Tornado handlers - You can run Tornado apps on the standard
asyncioevent loop - Third-party async libraries (like
asyncpg,aioredis) work with Tornado - You can mix Tornado and
asynciocode in the same application
When to choose Tornado
Good fit:
- Long-lived connections (WebSockets, SSE, long polling)
- Real-time applications (chat, notifications, live updates)
- Services that need fine-grained control over the networking layer
- Existing Tornado codebases that work well
Less ideal:
- New REST APIs (FastAPI or Starlette offer better developer experience)
- CRUD applications (Django provides much more out of the box)
- Teams unfamiliar with async programming
Common misconception
People often think Tornado is obsolete because asyncio now exists and newer frameworks like FastAPI are popular. But Tornado’s maturity is an asset — it has 15+ years of production battle-testing, a stable API, and deep integration with Python’s async ecosystem. For teams already using it, there’s rarely a compelling reason to migrate.
The one thing to remember: Tornado pioneered async Python web development and remains a strong choice for applications that need to hold thousands of simultaneous connections open — something it was solving years before Python’s async ecosystem existed.
See Also
- Python Aiohttp Client Understand Aiohttp Client through a practical analogy so your Python decisions become faster and clearer.
- Python Api Client Design Why building your own API client in Python is like creating a TV remote that only has the buttons you actually need.
- Python Api Documentation Swagger Swagger turns your Python API into an interactive playground where anyone can click buttons to try it out — no coding required.
- Python Api Mocking Responses Why testing with fake API responses is like rehearsing a play with stand-ins before the real actors show up.
- Python Api Pagination Clients Why APIs send data in pages, and how Python handles it — like reading a book one chapter at a time instead of swallowing the whole thing.