The official blog of Taveo

All things related to click tracking, digital marketing and web analytics

Why I am still using in 2017 – and you should be too is a python web framework was created by Aaron Swartz back in 2005. Over the years it has been updated here and there (python3 support is in!), but it has mostly stuck to its minimalist roots. This article assumes you are somewhat familiar with python web frameworks, like Django, CherryPy and of course

Whenever I start a new web based project I always start with (and peewee for the database stuff) for my server-side environment and you should too, here’s why.

First and foremost, (and peewee) are incredibly simple to understand and start using. Instead of spending multiple days trying to figure out how to layout your Django directory structure (I’m ashamed to admit this actually happened to me..too much conflicting advice maybe) you can breeze right past that part and start writing code! ( hint: you almost always create 2 directories “static” and “templates”). The hello world consists of about 8 lines of python code. It is straightforward and you can understand what every line is doing. Do not underestimate the hidden costs of complexity. Whether this is a B2B app with 20+ developers or a 1 man side project, keeping your software stack simple will always be beneficial.

Simple and Powerful!?

Don’t let this simplicity trick you into thinking is not powerful enough, because that is simply not true. Let me provide you with a short list of things is capable of:

  • URL pattern matching is based on python regex (re) module. If you can dream it, there is probably a regex that can parse it.
  • Built in support for sessions (via cookies), backed by files or by a database.
  • Supports various “hooks”, including pre and post request.
  • Has a built-in web server for development / testing.
  • Full templating engine
  • Built in web server automatically serves static content.
  • Fully WSGI compliant. handles the dirty details of processing a HTTP request and lets you handle the rest. Have a look at Djangos documentation on url handling. Lets compare that to’s

It’s just 2 lines of code. you define tuples that consist of a regex (“/.*”) and a python class name (“hello”) to call when this regex matches. goes down the list of your urls until it finds a match and invokes a class method once it does. No need to setup a bunch of boilerplate to get that going. Have a large project with 100’s or thousands of urls? Put them into a separate file when it gets complicated. No need to make it overly complex now. I could write a bunch more comparisons how various frameworks do things, but I think I have made my point. It’s hard to get much simpler than the way does it. Easy to understand, powerful when needed.

Your project grows with you

One of the best features of is that as your project grows more complex, it can grow with you, without much refactoring. As your simple site becomes a larger site, you can define multiple “web.template.render” objects, which can start a hierarchy of sorts. You can also create sub applications. You define a url regular expression in your main app and instead of mapping that to a class, you map it to a python module. All urls matching that prefix will be sent to that sub application. The sub application code is exactly the same as your main app, it doesn’t even need to know it is a sub app!

Code written for is easier to understand and maintain in the long run. Out of the box it can do 90% of what more modern framework can do, that last 10% is available via pip and some glue code. For example, I recently added memcached support into one of my projects. That consisted of me installing pylibmc, writing ~190 lines of glue code as a support library and calling that library 3 times in my code (fetch Key, put Key, expire Key). I would have spent more time editing my Django config file to add support.

What about CherryPy?

Some might point out CherryPy, which is also very minimalist. I have used CherryPy on multiple occasions and most times my project has started out simple enough, but eventually complexity creep starts setting in. At work a few years back we added CherryPy to our SQLAlchemy based project, it was not simple or straight forward (we used a modified version of the code on this page and got it working eventually). Here is how to do the same thing in Integrating with peewee is even easier.

My overall point is that is simple yet still very powerful. It doesn’t hide what it is doing behind magic things and doesn’t hold your hand or get it your way. is written and constructed in such a way that it leads to very simplistic code. It doesn’t provide modules or multiple layers of configuration and that is a good thing. forces you to write that yourself, which is always better than relying on module magic. You can spend X hours reading up on the module and how to integrate or you can spend the same amount of time inside your app coding the solution.

What about performance?

In various benchmarks, would probably perform somewhere in the middle of the pack. Are there faster frameworks out there? I’m sure there are. If you are at the point where performance is actually a problem, just perform the following:

  1. Install uWSGI.
  2. Install gevent
  3. “Monkey Patch” gevent into

Honestly, it is that simple (ok ok, you probably have to move beyond sqlite, implement DB connection pooling, etc. But all of that can be done in peewee in an afternoon, very simple and starighforward).

If you do somehow actually bump up against the edge of performance, go have a look at the source. That happens to be fairly simple as well. Find the hotspots and start improving!


Email this to someoneTweet about this on TwitterShare on FacebookShare on RedditPin on PinterestDigg thisShare on Google+Share on StumbleUpon