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

Welcome! You are about to start on a journey to learn how to create web applications with Python and the Flask framework. The video above will give you an overview of the contents of this tutorial. In this first chapter, you are going to learn how to set up a Flask project. By the end of this chapter you are going to have a simple Flask web application running on your computer!

For your reference, below is a list of the articles in this series.

Note 1: If you are looking for the legacy version of this tutorial, it's here.

Note 2: If you would like to support my work on this blog, or just don't have patience to wait for weekly articles, I am offering the complete version of this tutorial packaged as an ebook or a set of videos. For more information, visit courses.miguelgrinberg.com.

All the code examples presented in this tutorial are hosted on a GitHub repository. Downloading the code from GitHub can save you a lot of typing, but I strongly recommend that you type the code yourself, at least for the first few chapters. Once you become more familiar with Flask and the example application you can access the code directly from GitHub if the typing becomes too tedious.

At the beginning of each chapter, I'm going to give you three GitHub links that can be useful while you work through the chapter. The Browse link will open the GitHub repository for Microblog at the place where the changes for the chapter you are reading were added, without including any changes introduced in future chapters. The Zip link is a download link for a zip file including the entire application up to and including the changes in the chapter. The Diff link will open a graphical view of all the changes that were made in the chapter you are about to read.

The GitHub links for this chapter are: Browse, Zip, Diff.

Installing Python

If you don't have Python installed on your computer, go ahead and install it now. If your operating system does not provide you with a Python package, you can download an installer from the Python official website. If you are using Microsoft Windows along with WSL or Cygwin, note that you will not be using the Windows native version of Python, but a Unix-friendly version that you need to obtain from Ubuntu (if you are using WSL) or from Cygwin.

To make sure your Python installation is functional, you can open a terminal window and type python3, or if that does not work, just python. Here is what you should expect to see:

$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> _

The Python interpreter is now waiting at an interactive prompt, where you can enter Python statements. In future chapters you will learn what kinds of things this interactive prompt is useful for. But for now, you have confirmed that Python is installed on your system. To exit the interactive prompt, you can type exit() and press Enter. On the Linux and Mac OS X versions of Python you can also exit the interpreter by pressing Ctrl-D. On Windows, the exit shortcut is Ctrl-Z followed by Enter.

Installing Flask

The next step is to install Flask, but before I go into that I want to tell you about the best practices associated with installing Python packages.

In Python, packages such as Flask are available in a public repository, from where anybody can download them and install them. The official Python package repository is called PyPI, which stands for Python Package Index (some people also refer to this repository as the "cheese shop"). Installing a package from PyPI is very simple, because Python comes with a tool called pip that does this work (in Python 2.7 pip does not come bundled with Python and needs to be installed separately).

To install a package on your machine, you use pip as follows:

$ pip install <package-name>

Interestingly, this method of installing packages will not work in most cases. If your Python interpreter was installed globally for all the users of your computer, chances are your regular user account is not going to have permission to make modifications to it, so the only way to make the command above work is to run it from an administrator account. But even without that complication, consider what happens when you install a package as above. The pip tool is going to download the package from PyPI, and then add it to your Python installation. From that point on, every Python script that you have on your system will have access to this package. Imagine a situation where you have completed a web application using version 0.11 of Flask, which was the most current version of Flask when you started, but now has been superseeded by version 0.12. You now want to start a second application, for which you'd like to use the 0.12 version, but if you replace the 0.11 version that you have installed you risk breaking your older application. Do you see the problem? It would be ideal if it was possible to install Flask 0.11 to be used by your old application, and also install Flask 0.12 for your new one.

To address the issue of maintaining different versions of packages for different applications, Python uses the concept of virtual environments. A virtual environment is a complete copy of the Python interpreter. When you install packages in a virtual environment, the system-wide Python interpreter is not affected, only the copy is. So the solution to have complete freedom to install any versions of your packages for each application is to use a different virtual environment for each application. Virtual environments have the added benefit that they are owned by the user who creates them, so they do not require an administrator account.

Let's start by creating a directory where the project will live. I'm going to call this directory microblog, since that is the name of the application:

$ mkdir microblog
$ cd microblog

If you are using a Python 3 version, virtual environment support is included in it, so all you need to do to create one is this:

$ python3 -m venv venv

With this command, I'm asking Python to run the venv package, which creates a virtual environment named venv. The first venv in the command is the name of the Python virtual environment package, and the second is the virtual environment name that I'm going to use for this particular environment. If you find this confusing, you can replace the second venv with a different name that you want to assign to your virtual environment. In general I create my virtual environments with the name venv in the project directory, so whenever I cd into a project I find its corresponding virtual environment.

Note that in some operating systems you may need to use python instead of python3 in the command above. Some installations use python for Python 2.x releases and python3 for the 3.x releases, while others map python to the 3.x releases.

After the command completes, you are going to have a directory named venv where the virtual environment files are stored.

If you are using any version of Python older than 3.4 (and that includes the 2.7 release), virtual environments are not supported natively. For those versions of Python, you need to download and install a third-party tool called virtualenv before you can create virtual environments. Once virtualenv is installed, you can create a virtual environment with the following command:

$ virtualenv venv

Regardless of the method you used to create it, you should have your virtual environment created. Now you have to tell the system that you want to use it, and you do that by activating it. To activate your brand new virtual environment you use the following command:

$ source venv/bin/activate
(venv) $ _

If you are using a Microsoft Windows command prompt window, the activation command is slightly different:

$ venv\Scripts\activate
(venv) $ _

When you activate a virtual environment, the configuration of your terminal session is modified so that the Python interpreter stored inside it is the one that is invoked when you type python. Also, the terminal prompt is modified to include the name of the activated virtual environment. The changes made to your terminal session are all temporary and private to that session, so they will not persist when you close the terminal window. If you work with multiple terminal windows open at the same time, it is perfectly fine to have different virtual environments activated on each one.

Now that you have a virtual environment created and activated, you can finally install Flask in it:

(venv) $ pip install flask

If you want to confirm that your virtual environment now has Flask installed, you can start the Python interpreter and import Flask into it:

>>> import flask
>>> _

If this statement does not give you any errors you can congratulate yourself, as Flask is installed and ready to be used.

A "Hello, World" Flask Application

If you go to the Flask website, you are welcomed with a very simple example application that has just five lines of code. Instead of repeating that trivial example, I'm going to show you a slightly more elaborate one that will give you a good base structure for writing larger applications.

The application will exist in a package. In Python, a sub-directory that includes a __init__.py file is considered a package, and can be imported. When you import a package, the __init__.py executes and defines what symbols the package exposes to the outside world.

Let's create a package called app, that will host the application. Make sure you are in the microblog directory and then run the following command:

(venv) $ mkdir app

The __init__.py for the app package is going to contain the following code:

app/__init__.py: Flask application instance

from flask import Flask

app = Flask(__name__)

from app import routes

The script above simply creates the application object as an instance of class Flask imported from the flask package. The __name__ variable passed to the Flask class is a Python predefined variable, which is set to the name of the module in which it is used. Flask uses the location of the module passed here as a starting point when it needs to load associated resources such as template files, which I will cover in Chapter 2. For all practical purposes, passing __name__ is almost always going to configure Flask in the correct way. The application then imports the routes module, which doesn't exist yet.

One aspect that may seem confusing at first is that there are two entities named app. The app package is defined by the app directory and the __init__.py script, and is referenced in the from app import routes statement. The app variable is defined as an instance of class Flask in the __init__.py script, which makes it a member of the app package.

Another peculiarity is that the routes module is imported at the bottom and not at the top of the script as it is always done. The bottom import is a workaround to circular imports, a common problem with Flask applications. You are going to see that the routes module needs to import the app variable defined in this script, so putting one of the reciprocal imports at the bottom avoids the error that results from the mutual references between these two files.

So what goes in the routes module? The routes are the different URLs that the application implements. In Flask, handlers for the application routes are written as Python functions, called view functions. View functions are mapped to one or more route URLs so that Flask knows what logic to execute when a client requests a given URL.

Here is your first view function, which you need to write in the new module named app/routes.py:

app/routes.py: Home page route

from app import app

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

This view function is actually pretty simple, it just returns a greeting as a string. The two strange @app.route lines above the function are decorators, a unique feature of the Python language. A decorator modifies the function that follows it. A common pattern with decorators is to use them to register functions as callbacks for certain events. In this case, the @app.route decorator creates an association between the URL given as an argument and the function. In this example there are two decorators, which associate the URLs / and /index to this function. This means that when a web browser requests either of these two URLs, Flask is going to invoke this function and pass the return value of it back to the browser as a response. If this does not make complete sense yet, it will in a little bit when you run this application.

To complete the application, you need to have a Python script at the top-level that defines the Flask application instance. Let's call this script microblog.py, and define it as a single line that imports the application instance:

microblog.py: Main application module

from app import app

Remember the two app entities? Here you can see both together in the same sentence. The Flask application instance is called app and is a member of the app package. The from app import app statement imports the app variable that is a member of the app package. If you find this confusing, you can rename either the package or the variable to something else.

Just to make sure that you are doing everything correctly, below you can see a diagram of the project structure so far:


Believe it or not, this first version of the application is now complete! Before running it, though, Flask needs to be told how to import it, by setting the FLASK_APP environment variable:

(venv) $ export FLASK_APP=microblog.py

If you are using Microsoft Windows, use set instead of export in the command above.

Are you ready to be blown away? You can run your first web application, with the following command:

(venv) $ flask run
 * Serving Flask app "microblog"
 * Running on (Press CTRL+C to quit)

After the server initializes it will wait for client connections. The output from flask run indicates that the server is running on IP address, which is always the address of your own computer. This address is so common that is also has a simpler name that you may have seen before: localhost. Network servers listen for connections on a specific port number. Applications deployed on production web servers typically listen on port 443, or sometimes 80 if they do not implement encryption, but access to these ports require administration rights. Since this application is running in a development environment, Flask uses the freely available port 5000. Now open up your web browser and enter the following URL in the address field:


Alternatively you can use this other URL:


Do you see the application route mappings in action? The first URL maps to /, while the second maps to /index. Both routes are associated with the only view function in the application, so they produce the same output, which is the string that the function returns. If you enter any other URL you will get an error, since only these two URLs are recognized by the application.

Hello, World!

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

Congratulations, you have completed the first big step to become a web developer!

Before I end this chapter, I want to mention one more thing. Since environment variables aren't remembered across terminal sessions, you may find tedious to always have to set the FLASK_APP environment variable when you open a new terminal window. Starting with version 1.0, Flask allows you to register environment variables that you want to be automatically imported when you run the flask command. To use this option you have to install the python-dotenv package:

(venv) $ pip install python-dotenv

Then you can just write the environment variable name and value in a .flaskenv file in the top-level directory of the project:

.flaskenv: Environment variables for flask command


Doing this is optional. If you prefer to set the environment variable manually, that is perfectly fine, as long as you always remember to do it.


  • #276 Jakob said 2019-03-18T09:19:50Z

    Thank you for making these great tutorials. When i start the virtual server in my venv with flask run what is the home directory for this server? i build a small app to give users access to certain files in a folder but the virtual server does not see my regular root directory. Where should i save my files to make it work in the venv for testing purposes. Sorry if the questions sounds stupid. Jakob

  • #277 Miguel Grinberg said 2019-03-18T09:39:33Z

    The Flask server is not primarily made to serve static files, in the way other web servers are, so it isn't a great server for this purpose. See the following question in Stack Overflow for one way to do it: https://stackoverflow.com/questions/20646822/how-to-serve-static-files-in-flask.

  • #278 swordfish said 2019-03-20T16:16:31Z

    Pip install flask seemed to work, but python3 wouldn't import flask. I has to install python3-pip and use pip3 install flask.

  • #279 mpp said 2019-03-22T15:43:59Z

    Hello I have noobish problem :( followed directory structure and got

    ImportError: cannot import name 'routes' from 'app.app' (c:\microblog\app\app.py)

    I use python3 where init is not needed , so I assumed that app is inheriting its capabilities

  • #280 Miguel Grinberg said 2019-03-22T22:28:50Z

    @mpp: you are not using the same project structure that I'm using, so I have no way to know what you have in your project. init.py files are optional only when they are empty, which is not the case in this case.

  • #281 xarpy said 2019-03-25T17:03:50Z

    Hi Miguel, how are you?(Sorry for the slightest bit of English.) First of all, your tutorial has helped me a lot in learning the flask package and its extensions, thank you for this fantastic support. I would like your support in solving a problem that has happened in 2 particular projects. After finishing the microservices I came across a problem to initialize the service. Being the same below, I make use of the miniconda with flask 1.0.2 and believing that the problem could have been error in the construction of the code I made a git clone of your project to test, which presents the same error. Was there any solution? Could it be a flask package problem?

    Error: Traceback (most recent call last): File "/home/xarpy/opt/miniconda3/envs/commands/lib/python3.6/site-packages/flask/cli.py", line 330, in call rv = self._load_unlocked() File "/home/xarpy/opt/miniconda3/envs/commands/lib/python3.6/site-packages/flask/cli.py", line 317, in _load_unlocked self._app = rv = self.loader() File "/home/xarpy/opt/miniconda3/envs/commands/lib/python3.6/site-packages/flask/cli.py", line 372, in load_app app = locate_app(self, import_name, name) File "/home/xarpy/opt/miniconda3/envs/commands/lib/python3.6/site-packages/flask/cli.py", line 246, in locate_app 'Could not import "{name}".'.format(name=module_name) flask.cli.NoAppException: Could not import "microblog".

  • #282 Miguel Grinberg said 2019-03-25T22:08:05Z

    @xarpy: your current directory when you run the application needs to be the directory where microblog.py is located. Any chance you are running the app from some other directory?

  • #283 xarpy said 2019-03-26T17:19:53Z

    Thank you very much for the support Miguel, I finally understood the error. In fact, the problem found was not in the directory, but in the FLASK_APP environment variable. Because when he followed his tutorial and executed the "flask run" command, he complained about not finding the correct path of the script. To solve, I only had to pass the complete path (exp: "/home/admin/microblog.01/microblog.py") and I was able to run the application. I think it was a particular problem, but it is a hint for others who have the same problem. Thanks for the support Miguel.

  • #284 Dan said 2019-03-26T20:07:21Z

    Hi Miguel,

    Thanks a lot for your contribution to the community. Your tutorial are very thorough and helpful.

    I am struggling with .flaskenv and .env. I don't like having .env within my_project folder as shown below because is within the scope of Git-eligible files. Although .gitignore is set up not to pick .env files I would like to avoid accidents.

    When I place .flaskenv and .env within my_project the whole app works just fine. If I try to move .env one folder up to my_project's parent folder, flask complains with typical "flask.cli.noappexception: could not import "app". It seems that dotenv is actually overriding fully .flaskenv with .env as .env is found later and sort of first on the stack to be popped up.

    When placing both .flaskenv and .env in myproject's parent folder I have the same exception. Only when I move them into my_project I get the app running.

    Not a big deal though. I can find a workaround. . ├── README.md ├── my_project │   ├── init.py │   ├── admin │   │   ├── init.py │   │   ├── forms.py │   │   └── views.py │   ├── app.py │   ├── config.py │   ├── static │   │   ├── admin │   │   │   └── main.css │   │   └── main.css │   └── templates │   └── admin │   ├── layout.html │   └── login.html └── tests ├── init.py └── test_admin.py

    Thanks in advance.

    Best, Dan.

  • #285 Miguel Grinberg said 2019-03-26T23:03:47Z

    @Dan: I don't put the .env and .flaskenv files inside the application package, I put them outside, just like you want. Take a look at my project files to see how I did it.

  • #286 Andrew P said 2019-03-30T03:18:52Z

    Hi Miguel, Just bought your book and could not get the app to run as I run into this error: "ModuleNotFoundError: No module named 'blocks'. Otherwise, I think I have installed everything that was required:

    pip install flask_sqlalchemy pip install flask_migrate pip install flask_login pip install flask_mail pip install flask_bootstrap pip install flask_moment pip install flask_babel pip install elasticsearch pip install redis pip install rq pip install dotenv - do not have to run this pip install python-dotenv pip install jwt pip install flask_httpauth pip install flask_wtf pip install guess_language

    and did even:

    export FLASK_APP=microblog.py

    Thanks for your help.

  • #287 Miguel Grinberg said 2019-03-30T09:48:08Z

    @Andrew: I do not know what "blocks" is. Can you show me a complete stack trace of the error? That should indicate which line of code is wrong.

  • #288 Ka said 2019-04-09T00:38:25Z

    Hello, First, thanks for all your great work. I have your book, 2nd edition and it's really great. However, I am a beginner, that needs Python Flask Restful API only, with all the authorization. The book mentions Rest as an addition to the main app. Is there any of your resource you could recommend for the aforementioned implementation (front-end would be Angular, and maybe a mobile app at some point)? Did you think of maybe writing a smaller book on Python Flask Restful implementation? Thanks

  • #289 Miguel Grinberg said 2019-04-09T17:44:56Z

    @Ka: I have written a few articles about REST, you can find them in their own category in this blog (see the categories on the right sidebar). I have also spoken about REST at PyCon conferences, you can find those talks on YouTube.

  • #290 Robert Waelder said 2019-04-20T16:45:06Z

    Thank you so much for this tutorial Miguel! I am new to Python and this tutorial is very helpful. I seem to be getting an error when running the command "flask run" in the microblog directory:

    Serving Flask app "microblog.py" Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. Debug mode: off Usage: flask run [OPTIONS]

    Error: While importing "microblog", an ImportError was raised:

    Traceback (most recent call last): File "/Users/robzilla/pythonpractice/microblog/venv/lib/python3.7/site-packages/flask/cli.py", line 235, in locate_app import(module_name) File "/Users/robzilla/pythonpractice/microblog/microblog.py", line 1, in from app import app ImportError: cannot import name 'app' from 'app' (unknown location)

    I checked all the files, and it seems like everything is exactly written as in the tutorial. What might I be missing? Did I maybe install something incorrectly?

  • #291 Miguel Grinberg said 2019-04-21T10:33:54Z

    @Robert: the microblog.py and the "app" directory need to be at the same level, so a directory list of your pythonpractice/microblog folder should show both. The error that you are getting suggests that they are not. You can download a copy of this project from the GitHub links at the top of this article, that should make it easier for you to spot the error on your own.

  • #292 Iduntyr said 2019-04-25T20:16:55Z

    Hello, Miguel,

    I would also like to thank you for this interesting tutorial. I'm working through the tutorial on a Raspbian. Like Robert, I have the problem that the code is no longer executable since about 5 days. Also your provided code does not work. If I rename the app folder to apps there is no ImportError anymore, but now I get the error AttributeError module 'apps.app' has no attribute 'route'. If I use the attribute route in app.py (or init.py ) it works, as soon as I outsource this function it doesn't work, strangely enough. What could be the reason?

  • #293 Miguel Grinberg said 2019-04-26T07:20:21Z

    @Iduntyr: you've made a reference to an app.py module. What is that? I don't have any files named app.py in this tutorial. I suspect that file is causing your problems, try removing it.

  • #294 Billy Arante said 2019-05-03T03:13:02Z

    Thank you Miguel for creating this amazing tutorial to Flask!

  • #295 Kees Smit said 2019-05-03T12:19:28Z

    Hi Miguel,

    Your Flask tutorial was a big help for me on my little project with LEGO Mindstorms. I also used your tutorial for video streaming with Flask. See the result on my YouTube channel (https://youtu.be/SdDlvxnTCy0) and on GIthub (https://github.com/KWSmit/KSmRover). On several places I mentioned your name and tutorials, I hope that's ok by you.

    Kind regards,

    Kees Smit

  • #296 Alex Smith said 2019-05-19T01:18:01Z

    Something I found useful after some googling is getting virtualenv to use python3 by default. Most things have finally moved past python2 thankfully but sadly Ubuntu doesn't it make easy to use venv.

    So when making your virtualenviroment add "-p python3.6"(at the time of this comment at least) to use the latest version of python3 by default in your venv.

    Example of a full command would be.

    "virtualenv -p python3.6 venv"

    Other than that I had no issues if I was using something like Arch instead of ubuntu.

  • #297 Miguel Grinberg said 2019-05-19T22:57:14Z

    @Alex: you do not need virtualenv to create virtual environments in Python 3, that is only required for Python 2. See my instructions above for how to do it just with Python 3 and without any additional dependencies.

  • #298 Jurugo Brian said 2019-05-29T13:03:12Z

    Hey Miguel, Nice article however I thought it would have been better if you had given the package (app) a different name from the Flask object (app). Otherwise it ends up confusing especially to someone like me who is just learning the flask framework.

  • #299 Miguel Grinberg said 2019-05-29T13:42:05Z

    @Jurugo: This is actually covered in the article, where I explain the meaning of the two apps and then go on to say: "If you find this confusing, you can rename either the package or the variable to something else.". Using these two apps is common in Flask applications, so I prefer to explain this pattern and expose you to it instead of ignoring it.

  • #300 Michael said 2019-05-31T14:56:35Z

    Great, thank you for sharing! Can't wait to have a little free time and get into this!

Leave a Comment