The Flask Mega-Tutorial, Part I: Hello, World!

(Great news! There is a new version of this tutorial!)

This is the first article in a series where I will be documenting my experience writing web applications in Python using the Flask microframework.

NOTE: This article was revised in September 2014 to be in sync with current versions of Python and Flask.

Here is an index of all the articles in the series that have been published to date:

My background

I'm a software engineer with double digit years of experience developing complex applications in several languages. I first learned Python as part of an effort to create bindings for a C++ library at work.

In addition to Python, I've written web apps in PHP, Ruby, Smalltalk and believe it or not, also in C++. Of all these, the Python/Flask combination is the one that I've found to be the most flexible.

UPDATE: I have written a book titled "Flask Web Development", published in 2014 by O'Reilly Media. The book and the tutorial complement each other, the book presents a more updated usage of Flask and is, in general, more advanced than the tutorial, but some topics are only covered in the tutorial. Visit http://flaskbook.com for more information.

The application

The application I'm going to develop as part of this tutorial is a decently featured microblogging server that I decided to call microblog. Pretty creative, I know.

These are some of the topics I will cover as we make progress with this project:

  • User management, including managing logins, sessions, user roles, profiles and user avatars.
  • Database management, including migration handling.
  • Web form support, including field validation.
  • Pagination of long lists of items.
  • Full text search.
  • Email notifications to users.
  • HTML templates.
  • Support for multiple languages.
  • Caching and other performance optimizations.
  • Debugging techniques for development and production servers.
  • Installation on a production server.

So as you see, I'm going pretty much for the whole thing. I hope this application, when finished, will serve as a sort of template for writing other web applications.


If you have a computer that runs Python then you are probably good to go. The tutorial application should run just fine on Windows, OS X and Linux. Unless noted, the code presented in these articles has been tested against Python 2.7 and 3.4, though it will likely be okay if you use a newer 3.x release.

The tutorial assumes that you are familiar with the terminal window (command prompt for Windows users) and know the basic command line file management functions of your operating system. If you don't, then I recommend that you learn how to create directories, copy files, etc. using the command line before continuing.

Finally, you should be somewhat comfortable writing Python code. Familiarity with Python modules and packages is also recommended.

Installing Flask

Okay, let's get started!

If you haven't yet, go ahead and install Python.

Now we have to install Flask and several extensions that we will be using. My preferred way to do this is to create a virtual environment where everything gets installed, so that your main Python installation is not affected. As an added benefit, you won't need root access to do the installation in this way.

So, open up a terminal window, choose a location where you want your application to live and create a new folder there to contain it. Let's call the application folder microblog.

If you are using Python 3, then cd into the microblog folder and then create a virtual environment with the following command:

$ python -m venv flask

Note that in some operating systems you may need to use python3 instead of python. The above command creates a private version of your Python interpreter inside a folder named flask.

If you are using any other version of Python older than 3.4, then you need to download and install virtualenv.py before you can create a virtual environment. If you are on Mac OS X, then you can install it with the following command:

$ sudo easy_install virtualenv

On Linux you likely have a package for your distribution. For example, if you use Ubuntu:

$ sudo apt-get install python-virtualenv

Windows users have the most difficulty in installing virtualenv, so if you want to avoid the trouble then install Python 3. If you want to install virtualenv on Windows then the easiest way is by installing pip first, as explaned in this page. Once pip is installed, the following command installsvirtualenv`:

$ pip install virtualenv

We've seen above how to create a virtual environment in Python 3. For older versions of Python that have been expanded with virtualenv, the command that creates a virtual environment is the following:

$ virtualenv flask

Regardless of the method you use to create the virtual environment, you will end up with a folder named flask that contains a complete Python environment ready to be used for this project.

Virtual environments can be activated and deactivated, if desired. An activated environment adds the location of its bin folder to the system path, so that for example, when you type python you get the environment's version and not the system's one. But activating a virtual environment is not necessary, it is equally effective to invoke the interpreter by specifying its pathname.

If you are on Linux, OS X or Cygwin, install flask and extensions by entering the following commands, one after another:

$ flask/bin/pip install flask
$ flask/bin/pip install flask-login
$ flask/bin/pip install flask-openid
$ flask/bin/pip install flask-mail
$ flask/bin/pip install flask-sqlalchemy
$ flask/bin/pip install sqlalchemy-migrate
$ flask/bin/pip install flask-whooshalchemy
$ flask/bin/pip install flask-wtf
$ flask/bin/pip install flask-babel
$ flask/bin/pip install guess_language
$ flask/bin/pip install flipflop
$ flask/bin/pip install coverage

If you are on Windows the commands are slightly different:

$ flask\Scripts\pip install flask
$ flask\Scripts\pip install flask-login
$ flask\Scripts\pip install flask-openid
$ flask\Scripts\pip install flask-mail
$ flask\Scripts\pip install flask-sqlalchemy
$ flask\Scripts\pip install sqlalchemy-migrate
$ flask\Scripts\pip install flask-whooshalchemy
$ flask\Scripts\pip install flask-wtf
$ flask\Scripts\pip install flask-babel
$ flask\Scripts\pip install guess_language
$ flask\Scripts\pip install flipflop
$ flask\Scripts\pip install coverage

These commands will download and install all the packages that we will use for our application.

"Hello, World" in Flask

You now have a flask sub-folder inside your microblog folder that is populated with a Python interpreter and the Flask framework and extensions that we will use for this application. Now it's time to write our first web application!

After you cd to the microblog folder, let's create the basic folder structure for our application:

$ mkdir app
$ mkdir app/static
$ mkdir app/templates
$ mkdir tmp

The app folder will be where we will put our application package. The static sub-folder is where we will store static files like images, javascripts, and cascading style sheets. The templates sub-folder is obviously where our templates will go.

Let's start by creating a simple init script for our app package (file app/__init__.py):

from flask import Flask

app = Flask(__name__)
from app import views

The script above simply creates the application object (of class Flask) and then imports the views module, which we haven't written yet. Do not confuse app the variable (which gets assigned the Flask instance) with app the package (from which we import the views module).

If you are wondering why the import statement is at the end and not at the beginning of the script as it is always done, the reason is to avoid circular references, because you are going to see that the views module needs to import the app variable defined in this script. Putting the import at the end avoids the circular import error.

The views are the handlers that respond to requests from web browsers or other clients. In Flask handlers are written as Python functions. Each view function is mapped to one or more request URLs.

Let's write our first view function (file app/views.py):

from app import app

def index():
    return "Hello, World!"

This view is actually pretty simple, it just returns a string, to be displayed on the client's web browser. The two route decorators above the function create the mappings from URLs / and /index to this function.

The final step to have a fully working web application is to create a script that starts up the development web server with our application. Let's call this script run.py, and put it in the root folder:

from app import app

The script simply imports the app variable from our app package and invokes its run method to start the server. Remember that the app variable holds the Flask instance that we created it above.

To start the app you just run this script. On OS X, Linux and Cygwin you have to indicate that this is an executable file before you can run it:

$ chmod a+x run.py

Then the script can simply be executed as follows:


On Windows the process is a bit different. There is no need to indicate the file is executable. Instead you have to run the script as an argument to the Python interpreter from the virtual environment:

$ flask\Scripts\python run.py

After the server initializes it will listen on port 5000 waiting for connections. Now open up your web browser and enter the following URL in the address field:


Alternatively you can use the following URL:


Do you see the route mappings in action? The first URL maps to /, while the second maps to /index. Both routes are associated with our view function, so they produce the same result. If you enter any other URL you will get an error, since only these two have been defined.

When you are done playing with the server you can just hit Ctrl-C to stop it.

And with this I conclude this first installment of this tutorial.

For those of you that are lazy typists, you can download the code from this tutorial below:

Download microblog-0.1.zip.

Note that you still need to install Flask as indicated above before you can run the application.

What's next

In the next part of the series we will modify our little application to use HTML templates.

I hope to see you in the next chapter.



  • #51 Miguel Grinberg said 2013-03-26T16:18:36Z

    @Yuen: you either put the "run.py" file in the wrong place, or you are missing the "app" module. The run.py script must be at the top, it should be at the same level as the app folder (i.e. when you get a directory listing of your top folder you should see both "run.py" and the "app" folder).

  • #52 Peter said 2013-03-27T05:58:19Z

    Miguel, nice technique to allow for multiple urls to point to one template view

  • #53 Nusek said 2013-03-31T15:04:03Z

    hi, firstly thank you soo much for the helpful tutorial. i have read all 1.part of tutorial and also all comments about it. but i still confused. first reason; i have copied your microblog-0.1.zip and unzip under microblog directory and clicked setup.py then setup done successfully, but whenever i type bla-bla-directory/microblog/flask/Scripts/python run.py, i always get the same error: (python: can't open file 'run.py': [Errno 2] No such file or directory).So, how can i hack this trouble? Second reason of i confused: when i copy "app" directory and "run.py" file under the microblog\flask\Scripts directory, i can execute "flask/Scripts/python run.py" command without any error. So, what should i do after this? (p.s. my system on WinXP and python2.7)

  • #54 Miguel Grinberg said 2013-03-31T16:31:18Z

    @Nusek: you should "cd" to the microblog directory so that "run.py" is in the current directory. Thta way you can just run it with "flask/Scripts/python run.py".

  • #55 Long said 2013-04-04T08:20:24Z

    Hi, Miguel Grinberg, can you tell me what does "#!flask/bin/python" exactly do ??? Thank you

  • #56 Miguel Grinberg said 2013-04-05T04:27:16Z

    @Long: this is called the "shebang line". On Windows it does nothing. On Unix-like systems like Linux or OS X it defines the interpreter that the system should use to execute the script. See http://en.wikipedia.org/wiki/Shebang_(Unix) for more information.

  • #57 Martin said 2013-04-12T09:29:43Z

    For installing flask via pip you coud add a shortcut, where all packages come in one line, like "flask/bin/pip install flask flask-login flup ...". For those who know what they are doing, it is way faster as you follow "don't repeat yourself" ;-)

  • #58 haloha said 2013-04-14T03:07:06Z

    ├── app │ ├── init.py │ ├── static │ └── templates ├── flask │ ├── bin │ │ ├── activate .... │ │ └── warnings.pyc │ └── lib64 -> lib ├── tmp ├── virtualenv.py └── virtualenv.pyc

    python app/init.py Traceback (most recent call last): File "app/init.py", line 1, in from flask import Flask ImportError: No module named flask

    i use CentOS release 6.3 (Final)

    how to fix it

    Thank you

  • #59 Miguel Grinberg said 2013-04-14T04:17:51Z

    @haloha: do you have Flask installed in your virtual environment? Run: this:

    flask/bin/pip freeze

    to see what modules are installed.

  • #60 Anthony said 2013-04-14T19:53:29Z

    Just wanted to say THANK YOU for this excellent article. And mention one thing that I think could be helpful to others. If you name the main folder something slightly different 'myapp' for example, then the 'from myapp import app" might make some more sense. I've done that and finally got it working, I just don't really understand where the above views.py is importing the app from (flask directly?) and what the from app import app statements are really doing, renaming the parent folder might help shed some light for me.

  • #61 Michael L said 2013-04-15T06:45:36Z

    Hope you don't mind another heroku problem. I am using the app folder structure from your tutorial (run.py in root directory, init.py in the app directory). My app uses heroku postgres via SQLAlchemy. It runs perfectly locally, but when I push to heroku and scale up the web process, here is what I get:

    at=error code=H12 desc="Request timeout" method=GET path=/login host=floating-wildwood-6203.herokuapp.com fwd="" dyno=web.1 connect=1ms service=30000ms status=503 bytes=0

    I was getting "connection already in use" in debug=true mode. Now I just get the timeout above.

    Any idea? Many thanks – this tutorial is tremendously useful for new coders.

  • #62 Miguel Grinberg said 2013-04-15T19:23:42Z

    @Michael: I'm currently working on deploying microblog to Heroku (to write about it here). So far I haven't seen any major issues, but your problem appears to be openid related. At least when I see timeouts during login it is always related to the response from the openid server not getting through for some reason.

  • #63 Anthony said 2013-04-21T18:19:32Z

    Sorry for the double post, but I'm still curious, does the folder structure require to be called 'app', 'template' and 'static' ? If not, what else needs to change? Can just the 'app' folder be renamed to something else?

  • #64 Miguel Grinberg said 2013-04-21T18:47:14Z

    @Anthony: the folder names are not set in stone, you can use any names you want. The "app" name in particular is the name of a module that gets imported, so instead of saying "from app import app" you will say "from mymodule import app".

  • #65 Joseph said 2013-05-05T07:46:07Z

    @Gator See: http://flask.pocoo.org/docs/installation/#virtualenv

    Follow the instructions up to and not including "System Wide Installation." Keep in mind that virtiualenv venv here will create a folder in your current directory, which you will then need to account for when writing run.py with: #!venv/bin/python

  • #66 Guy said 2013-05-06T16:58:59Z

    Hi Miguel,

    I got step 1 right away so that I could access it on my local machine but I could not figure out how to access the app from the Internet. After 3 hours of research I figured out that I needed to alter the iptables to allow access to port 5000. Is this common? I have ubuntu 12.04 installed on Linode. It would be great if you could add a section showing how to make the dev server available to the public. This would be helpful for people who can only access their servers via ssh and hence don't have access to a local graphical browser for testing. Its kind of annoying to use lynx. Thank you. Great tutorial.

  • #67 Miguel Grinberg said 2013-05-06T17:12:20Z

    @Guy: Hmm. I can think of two other ways you could get your development server working. You could change from port 5000 to port 80, which is likely open in your firewall. The risk aspect of this solution is that you will need to run your server from the root account (only root can listen on ports below 1024). The other (much better) option is to install a X client in your client PC and then configure your SSH session to use your client PC as the display server. Then you can use Firefox or any other GUI browser you like on your Linode VPS and the window will come to your PC.

  • #68 Don Arnold said 2013-05-09T02:29:08Z

    i just discovered this tutorial, and I must say it looks great. But I've one question/nitpick. Shouldn't the shebang in app.py be:


    since that's really where our interpreter is installed? I've no flask/bin directory after following your quite excellent installation instructions (thanks for supporting us poor Windows users).


  • #69 Miguel Grinberg said 2013-05-09T04:44:59Z

    @Don: on Windows the shebang isn't used, it is only used when you are on Unix like platforms. On Unix systems the virtual environment path to the interpreter is flask/bin/python, so if you want to have files that work on all platforms without changes then you want to have a shebang that is configured for Unix.

  • #70 Guy said 2013-05-10T20:15:36Z

    I'm getting the following error when I run the migration script. I'm still able to go through the tutorial without the migration functionality. I just figured I would share this error. It seems like the sqlalchemy exceptions library no longer exists after a little research.

    guyja@carbon:~/python/microblog$ ./db_create.py Traceback (most recent call last): File "./db_create.py", line 2, in from migrate.versioning import api File "/home/guyja/python/microblog/flask/lib/python2.7/site-packages/migrate/v ersioning/api.py", line 33, in from migrate.versioning import (repository, schema, version, File "/home/guyja/python/microblog/flask/lib/python2.7/site-packages/migrate/v ersioning/schema.py", line 10, in from sqlalchemy import exceptions as sa_exceptions ImportError: cannot import name exceptions

  • #71 Miguel Grinberg said 2013-05-10T20:55:25Z

    @Guy: This is explained in the Database article. You need to use sqlalchemy version 0.7.9. The problem occurs in version 0.8.x, due to the sqlalchemy-migrate project not being updated to be compatible with the 0.8.x sqlalchemy releases.

  • #72 Konstantinos said 2013-05-11T12:43:22Z

    Hello, I have a question please, whenever I try to create a new virtual environment naming it anything but 'flask', my app does not run, why is this? For example a created a virtual environment called 'myenv' and then I receive this 'ImportError: No module named myenv'.

  • #73 Miguel Grinberg said 2013-05-11T16:58:19Z

    @Konstantinos: you can use your own virtual environment name, but in the scripts when you say "import flask" you have to leave that alone. In this context "flask" is a module name, not a virtual environment name.

  • #74 Janden said 2013-05-14T23:27:21Z

    Thanks for this tutorial. I got as far as these lines:

    from flask import Flask

    app = Flask(name) from app import views

    and I got this error: from: can't read /var/mail/flask

    Can you help me out?

  • #75 Miguel Grinberg said 2013-05-15T00:26:19Z

    @Janden: how are you running the application?