8 great little Python web frameworks

Small is beautiful. Look to these Python web frameworks when you want speed and simplicity instead of feature sprawl.

Table of Contents
Show More
1 2 Page 2
Page 2 of 2

Pyramid’s slender testing and debugging tools do the trick. Bundle the debugtoolbar extension in a Pyramid app and you’ll get a clickable icon on every web page that generates details about the app’s execution, including a detailed traceback in the event of errors. Logging and unit testing are also present.

Pyramid’s documentation is excellent. In addition to a quick tour of the basics and a tutorial-style walk-through, you’ll find a set of community-contributed tutorials and a cookbook of common recipes. The latter includes deployment techniques for a slew of target environments, from Google App Engine to Nginx.

Pyramid supports both Python 2 and Python 3, but does not use Python 3’s async syntax. If you want to leverage async in Pyramid, see the aiopyramid project, which includes a scaffold for an async-powered “hello world” application. 


Designed for speed and simplicity, Sanic works with Python 3.6 or higher and uses Python’s async/await syntax (available as of Python 3.5) to let you create efficient web applications.

As with Flask or Bottle, a basic Sanic “hello world” runs about 10 lines of code, most of it imports and other boilerplate. The key difference is that application routes must be declared as async def functions, and you must use await to invoke these functions within your async code. If you’ve written async-powered applications before, you already have the hardest part under your belt.

Many of the mechanisms Sanic uses for handling connections and responses will be familiar. Requests and responses are just objects with familiar-looking properties, like uploaded files, forms, JSON objects, headers, and so on.

Applications with many routes become unwieldy to manage. Sanic addresses this with “blueprints,” objects that can describe groups of routes and allow you to manage them via high-level interface. Instead of writing each route explicitly, or using an excess of routes with variables, you can write a few blueprints to generically describe how the routes work in your app (e.g., /object/object_id/action). Blueprints can have common middleware, which is useful if you want to apply management functionality to some routes but not others.

Sanic also works with protocols other than HTTP. WebSocket endpoints require only a different decorator and a little more internal logic (e.g., awaiting and handling responses). Custom network protocols can be supported by subclassing asyncio.protocol.

Sanic deliberately leaves out functionality like database connectivity and HTML templating, while retaining the features one would use to plug in those capabilities: middleware, centralized application configuration, and so on.


Tornado is another tiny framework aimed at a specific use case: asynchronous networking applications. Tornado is well-suited for creating services that open a great many network connections and keep them alive—that is, anything involving WebSockets or long polling. Tornado 6.0 requires Python 3.5 or higher, and drops Python 2 support entirely.

Like Bottle or Falcon, Tornado omits features extraneous to its central purpose. Tornado has a built-in templating system for generating HTML and other output, and provides mechanisms for internationalization, form handling, cookie setting, user authentication, and CSRF protection. But it leaves out features, like form validation and an ORM, that are mainly for user-facing web apps.

Tornado excels at providing infrastructure to apps that need close control over asynchronous networking. For instance, Tornado provides not only a built-in asynchronous HTTP server, but also an asynchronous HTTP client. Thus, Tornado is well-suited to building apps, such as a web scraper or a bot, that query other sites in parallel and act on the returned data.

If you want to create an app that uses protocols other than HTTP, Tornado has you covered. Tornado provides access to low-level TCP connections and sockets to utilities like DNS resolvers, as well as to third-party authentication services, and it supports interoperation with other frameworks through the WSGI standard. The documentation, which is small but not sparse, includes ample examples for accomplishing all of this.

Tornado both leverages and complements Python’s native functionality for asynchronous behaviors. If you’re using Python 3.5, Tornado supports the built-in async and await keywords, which promise to give applications a speed boost. You can also use futures or callbacks to handle responses to events.

Tornado provides a library of synchronization primitives—semaphores, locks, and so on—to coordinate events between asynchronous coroutines. Note that Tornado normally runs single-threaded, so these primitives aren’t the same as their threading namesakes. However, if you want to run Tornado in parallel processes to leverage multiple sockets and cores, tools are available for doing so.

Tornado’s documentation covers each major concept in the framework and all of the major APIs in the model. Although it includes a sample application (a web crawler), it’s mainly for demonstrating Tornado’s queuing module.

Copyright © 2020 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2