From Zero to Deployment: Creating a Grocery List App within 30 minutes

Websites nowadays can be done rapidly without too much effort. Product releases tend to get up to speed all thanks to the open-source frameworks. I know why you’re here. You want to create a quick app that you may use for a hackathon. Well, you’re in the right place! Though the difference of mine is you’ll be making a little more effort than just copy-pasting templates and scaffold existing codes. I made this article for those who have little to possibly no experience of coding to get something started.

I’ll teach you from creating your own server up to deployment, ALL WITHIN 30 MINUTES! What you’ll build is a simple grocery list app wherein you could add some items, view the list, edit them and delete. Not only that. Everything is FREE of charge so no need to spend on anything! Sweet isn’t it? I’ll save the other details for later but for now, let’s get started!


If you want to have a preview of what we’ll be building, here’s the finished output:



Make sure you have these installed before you proceed!

    1. Text editor – Notepad++, Sublime text, whatever your preference is!
    2. Python – 2.7 and up
    3. Git – we’ll need this to store your repo and to use its commands to deploy later
    4. Heroku – The platform we’ll use to deploy later
    5. DB Browser for SQL Lite (optional) – This will be used to check your data in the database. This is better than typing CLI codes for the tutorial so we could see a better view
    6. pip – Is a package manager from python where we could easily acquire other libraries through it’s commands. Note that you need python first before acquiring this. Once your installation is done, type pip and ensure something appears


Just to be clear, here are the things we won’t be covering or at least make much detail:

  1. Basic Web development – Things like HTML and CSS. I’m not going to go through the basics.
  2. Python Basics – We’ll assume you know at least a bit of this language. Don’t worry, we won’t deal with anything complex
  3. SQL – This is the language where we’ll store our data and you’ll be seeing some basic syntaxes as we go along.
  4. Best Practices – We’ll do a lot of copy-pasting so don’t expect to implement best practices. Though we’re not totally jeopardizing our app.
  5. Front-end/Back-end architecture – we will need not create a good architecture. The essence of this tutorial is to teach you a quick ready-to-go app.


Note: If you really don’t know how to code, that’s alright. You may try to follow this tutorial then understand the concepts later. Best if you have even just a little knowledge on HTML, CSS, Python, and SQL so you could easily follow.


Alright let’s begin!

Note: By the way I’m using a Mac so any issues you might encounter along the way with a different OS might not be replicable to mine. Regardless, I’ll try to help.

1.) Creating your server

First thing’s first. Let’s make our server. Create a folder named “webproj” where we’ll be placing our project files. Next, open your Terminal (Command Prompt on Windows) then point your terminal to your webproj folder. I my case I had to type in “cd webproj“. Install flask by typing “pip install flask


Next, open your text editor then create a file called ““. We’ll be placing pretty much most of our back-end code there. Upon creating, do the following

from flask import Flask

app = Flask(__name__)

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

Basically, we’re writing a code wherein upon running the server will display a simple Hello World message. What the Flask(__name__) does is declare the Flask object and assign it to a variable app. Lastly, type in flask run to run the server. Open your browser then type in localhost:5000. You should see this:



Congratulations you just created a simple server! What you’ve done was to rurn your flask application. By default, apps that run in your local machine are called “localhost” and flask sets it to port 5000 by default.

2.) Linking your HTML page


You have seen how the display works but we don’t want that. We want to have our own custom design and we’ll do that through HTML and CSS. Let’s create a folder templates inside your webproj folder. Create a file called “index.html” then save it in your templates folder. Inside the index.html file, add the following



<h1>HELLO WORLD!</h1>



Lastly, go to your app.js then replace your import statement to from flask import Flask, render_template then replace the return statement into return render_template(‘index.html’)

from flask import Flask, render_template

app = Flask(__name__)

def index():
    return render_template('index.html')


Let’s see it in action! If you just installed your python and just followed this tutorial straight from installation, your debug mode has been turned off by default meaning, it will not automatically reflect changes when you changed something in your python code. We wouldn’t want to keep on restarting and re-stopping for every change right? So let’s make it automatic!

Go back to your terminal then type Ctrl + C to stop your server. Next, turn on your debug mode by typing export FLASK_DEBUG=1.

Note: In windows you use the set keyword, not the export.

Let’s run again our server by typing flask run. Go back to the browser then reload the page.

You will notice that debug mode was off when we started. Now it’s on thanks to the command!


This should be your output


Alright! We have our site working with our associated HTML! Flask by default looks for the HTML files inside the templates folder. If you want to structure out your folders, make sure to map out the directories directly upon calling it out on the render_template function (though we won’t be discussing this because again, we’ll not deal with best practices).

3. Adding styles through Bootstrap


Now that we have our HTML up, let’s make our design better using bootstrap and its templates. We will of course, not code things from scratch because again, I’m teaching you some hacks as well as being consistent with our RAPID prototyping. If you’re not familiar with bootstrap, this is a CSS framework that deals with all your styles in a way that by simply calling out their classes, all your problems will be solved!

First of, let’s create a folder named “static” inside your webproj folder.


This is where we’ll store all our CSS and Javascripts. Next up, we’ll download bootstrap on their website. You can search for bootstrap then download the zip file. To save you some trouble, here’s the link:

All you need to do is click that, right-click, then save as bootstrap.min.css in your static folder.

Saving the library to our local PC


That should be saved in the static folder.


We’ll link that later on on our HTML file. Next up, to get a bootstrap template.

4. Creating a master page and finishing our layout

Let’s beautify further our site!


4.1 Adding another css and linking the css into the web page

Now that the library is all set up, we’ll then get an HTML template on the bootstrap website.

There are plenty of templates to choose from. You can visit the sample in this link:

We’ll select the OffCanvas template. As you can see, there’s no code snippet nor download button. You have to check the source code then copy-paste from there.

The OffCanvas template. Perfect for what we need!


Right-click then view page source. After, we’ll copy-paste all the codes into your index.html


To make things easy, I’ll paste HTML code for you!

Note: I’ve removed some unnecessary code and edited some information to make it simple so the one you have downloaded will be different from this version. I suggest to just copy-paste the code here so you can accurately follow. Don’t worry, we’re still using the same code but we only edited/removed few lines.

Click here with good format.

Paste the code in your index.html

After, reload and look back in your website.

WOAAAH SURPRISED? Yes you’ll see that the website isn’t as what you expected. Why? Because we haven’t fixed our styles yet. It’s not loaded properly because we only copy-pasted the code. Let’s fix it!


Go back to your index.html then modify the following:


<link href="{{ url_for('static', filename='bootstrap.min.css') }}" rel="stylesheet">

Next, download the offsite css template on their site. To make this easier, click here, right-click then save as offcanvas.css then save it in your static folder. What the code does is url_for is a code to map the current directory of the project then ‘static‘ is the name of the folder. Obviously on the next argument, we place in the filename we’re looking for in that folder.


Adding the other css file


Go back to index.html then modify the following line

<link href="{{ url_for('static', filename='offcanvas.css') }}" rel="stylesheet">

Pretty similar to what we did earlier but a different file this time. Reload the browser and see what happens.


As you can see, the only difference is only the change of header. Though it’s not much of a difference, at least we have beautified the website a bit. There’s more in that CSS so we haven’t seen its true potential. Let’s move on to optimizing it a little bit by creating the master file and make all reusable codes stay in there.


4.2 Creating a master HTML file then linking children HTMLs

Let’s sort out the codes now. You’ll wonder eventually how to reuse some codes since they act the same on all pages. We’ll divide them through different files. Let’s create the master file by creating a new file called master.html then save it under templates folder. We’ll place all the reusable code here.  After, let’s go back at index.html, CUT and paste the following code.


Make sure you start from the top up to the <body> tag.

Next, CUT and paste the nav bar:


Ensure from the beginning up to the end of the <nav> tag you got that part.

Lastly, CUT and paste the scripts up to the last part of the last tag of HTML

Collectively, you master.html should look like this:

Your index.html should only contain the <main>….</main> tag and its internal elements.

Now let’s connect master.html and index.html.

In your master.html, add the following tag below the </nav> tag.

{% block content %}{% endblock %}


This is the code that links the contents of your index.html. Lastly, let’s go back to our index.html file and add the following lines:

Note: Never mind the indention for now. Let’s just go with the flow.

Line 1: {% extends 'master.html' %} 
Line 3: {% block content %}
Line 79: {% endblock %}

First 2 lines of code

At line 79 below

By just reading the code, you could already understand what it does. On the master.html, that’s the linking code going through it’s child content. On index.html, the first line of code tells which master file it should follow through (in this case, master.html) Then you’ll see a {block content} and {endblock} code. They indicate what will be our content for the master file.

5. Adding the form page and hyperlinks

Now for the last part of the front-end, we’ll be adding a page where you could enlist your entries and add links on your page for navigation

5.1 Adding links

This is easy. Just go to your master.html then add and delete the following:

Addurl_for(‘index’) and url_for(‘add’) on the home/add. The parameters inside this function is the function coming from your We already have the index function created. We’ll create the add function in a short while.

Delete: the other navigational codes within the <li> tags

Note: We’ll keep the search bar for design purposes even though we’re not going to use them later on 😛

On your, add the url_for library.



5.2 Adding the registration page

Now that we have the links all set, let’s add our registration.

Create a new file called add.html then save it on your templates folder. Leave it empty for now.


Next, in your, we’ll need to add a route that caters our registration page. Add the following lines of code (or just copy-paste the existing route then modify)

def add():
    return render_template('add.html')

Reload your web browser and you should see the following. You should be able to click the add tab and expect nothing on the page.

This is what your home page should look like. Lessened the nav menus above and the “add” menu should be clickable.


What the add page should look like. Nothing at the moment and not yet linked in the master.html.



5.3 Adding a template for the registration page

We’ll do like we did last time on our home page to beautify our page. We’ll go back to the examples page and borrow a template from the bootstrap framework. We’ll borrow the Checkout template. Just like before, right-click, view page source then copy-paste the content on your add.html.

A preview of the Checkout template. Right-click then View Page Source


What the add.html looks like fresh from the source.


We’ll then cleanup this code by removing unnecessary lines and linking it to the master page. Let’s delete the following:

First: Starting HTML tag up to beginning body tag; Lines 1 – 20

Note: Delete them first before proceeding to the second because the number line will change accordingly


Second: The scripts up to the ending HTML tag; From lines 219 – 250


Third: The summary row; Lines 11- 59


Fourth: Credit card Info; Lines 95 – 154


Now that all the unnecessary code out, let’s bind this page to our master file!

Add the following lines on the first line of add.html:

{% extends 'master.html' %}

{% block content %}

Lastly, add the endblock code at the bottom of the file:

{% endblock %}


Now reload the browser and your add page should change

This is it! Never mind the design for now to stretch to the right. I don’t need to preview the bottom part but it should reveal the submit button and the footer.


Tadaaa! We have a good-looking registration page!

We’re finally done with the major front-end components. Now let’s make this thing come to life by providing the backend!

6. Creating the database

We’ll begin creating our database. This is where we’ll be storing our data on our grocery list. We’ll be using the built-in library from python called sqlite.

To start-off, we’ll need to define first what fields do we need on our database. To keep things simple, the requirements we need are:

  • ID
  • Item name
  • Amount
  • Description
  • Date Created
  • Category

The first thing we need is to define these on an SQL file.


6.1 Creating the SQL file

Create a file called schema.sql. This is where we’ll place the table definition for our list. Inside it, add the following:


    item_name TEXT NOT NULL,
    description TEXT,
    category TEXT NOT NULL


If you know SQL there shouldn’t be much to explained but basically this is just defining our fields with their corresponding properties (wether it’s a text, character, or date). You’ll also see in the first line that it has a validation if the table exists or not. If it does, then drop and recreate.


6.2 Creating the database connection

Now for the complicating part. I won’t be breaking too much details as I’ll reuse the template provided by the official flask tutorial.

Create a new file called “” then save it in your project directory. Inside this file write the following code or just copy paste from this source:


“WHAT THE HECK DO THESE CODES DO?”, you ask. Here’s the summary

  • To connect to the database as well as closing it
  • Connecting to your main application making this file as a source of your database object
  • Has a command-line mechanism wherein if typed in your cmd/terminal, the code will execute (in which will initialize the database)
  • Lastly, to initialize (create) the database coming from the “schema.sql”

To know more line per line, read more here.

Next up, we’ll link this file to our then do some changes on our app initialization. On your, add and modify the following:

Line 2: add os and db on he import. os is an object to deal with the operating system while db is the as it belongs in the same folder with and the import name is considered to be the file name.
Line 4: Modify the Flask object, adding an additional parameter of instance_relative_config
Lines 5 - 28: A new function to integrate the data


import db, os

app = Flask(__name__, instance_relative_config=True)
    DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),

def create_app(test_config=None):

    if test_config is None:
        # load the instance config, if it exists, when not testing
        app.config.from_pyfile('', silent=True)
        # load the test config if passed in

    # ensure the instance folder exists
    except OSError:


    return app


Create a folder named “instance” in your project directory. This is the directory where our database file will be saved. Why was it saved there? It’s because of the app.instance_path you’ve written on the database mapping meaning, it will look for a folder named “instance” then map there by default (this is explained on the article I just linked but explain it here in case you have not time to read it).


Lastly, add the db.init_app(app) below the function

w’re all set! Let’s run the command. Go back to your terminal then type in flask init-db. make sure you are running it in the root of your project directory. You should see the message when you’ve successfully executed it


Inside your instance folder, you should see a flaskr.sqlite file created from the command.

We’ll dig deep later on with this file. What’s important is you have this existing on the folder. We now have our database ready to use


7. Integrating the registration page for saving

Let’s now connect our front-end to back-end so we could add some entries to our grocery list.


7.1 Fixing the HTML form

We’ll first fix our HTML codes so it could create a POST request going to the back end. Let’s go back to our add.html and modify the following:

Line 16: add method="post" on the form

Lines 16 - 32: Delete first name and last name (the portions highlighted)

Modify the first 2 fields and ensure they look like this. I deleted some properties and modified some texts.


Similarly, let’s do it on the next 2 fields below.


Note that the name attribute is important and that’s the key property for the back-end to know the value of our input.

I had to emphasize on the screenshot the description field since I forgot to place it at the time of making LOL. It total we should now have 4 fields.


Lastly, delete the unnecessary codes (the ones highlighted) and change the text on submit button.


Let’s look on our browser and check the updates.


Clean and simple! Now let’s move on to the back-end and integrate the saving mechanism.

7.2 Adding the Database query for saving.

On our, add the following codes:

Line 38 – Checks if the request method is POST

Lines 39 – 44 – Assign variables from form data, database then a declaration of an error variable to be used later

Line 46 – Check if all fields are filled up

Lines 50 – 56 – Create the SQL query to save data, assign success message then redirect to template

@app.route('/add', methods=('GET', 'POST'))
def add():

    if request.method == 'POST':
        item_name = request.form['item_name']
        description = request.form['description']
        amount = request.form['amount']
        category = request.form['category']
        dbo = db.get_db()
        error = None

        if not item_name or not description or not amount or not category:
            error = 'You have incomplete fields. Kindly double-check.'

        if error is None:
                'INSERT INTO list (item_name, description, amount, category) VALUES (?, ?, ?, ?)',
                (item_name, description, amount, category)
            flash('Successfully added an item!')
            return render_template('add.html')


    return render_template('add.html')

Let’s not forget to import our request and flash library. Request will be used to cater our HTTP requests while flash will deal with messages to prompt wether the database queries were a success or not.

Now let’s go back to the browser and test this out!



I’m entering fish, For breakfast, 100 and Food. Hit submit and it should save in the database.

Upon hitting submit you should see no response because we haven’t placed in our flash code yet however if that seemed to happen it means our data was saved! How do we verify? I am using a tool called DB Browser for SQLite and you can download it as well.


Then upon browsing we should see our entry


Lastly, let’s add a flash message so we could be prompted wether our entry has been saved in the database.

{% for message in get_flashed_messages() %}

{{ message }}

{% endfor %}



Let’s try it again with another entry

The hit submit then you’ll see a prompt

Now to proceed on displaying the data.


8. Displaying data

Now that we have data on our database, let’s display them on our home page. This should be quick and easy.


On our, replace your existing code with the following:


dbo = db.get_db()
    items = dbo.execute(
        'SELECT * FROM list'
    return render_template('index.html', items=items)

This is the SQL query to get all our items from the list table and the query result will be assign to the items variable.


Next, let’s bind this on our HTML home page. Delete the following tags on your index.html

The update tags aren’t needed



The other 2 rows on the username as well as the “All suggestions” hyperlink

Lastly, modify the following to make it look like this:


&amp;amp;amp;lt;div class="my-3 p-3 bg-white rounded box-shadow"&amp;amp;amp;gt;

&amp;amp;amp;lt;h6 class="border-bottom border-gray pb-2 mb-0"&amp;amp;amp;gt;Grocery List&amp;amp;amp;lt;/h6&amp;amp;amp;gt;

                {% for item in items %}

&amp;amp;amp;lt;div class="media text-muted pt-3"&amp;amp;amp;gt;
                    &amp;amp;amp;lt;img data-src="holder.js/32x32?theme=thumb&amp;amp;amp;amp;bg=007bff&amp;amp;amp;amp;fg=007bff&amp;amp;amp;amp;size=1" alt="" class="mr-2 rounded"&amp;amp;amp;gt;

&amp;amp;amp;lt;div class="media-body pb-3 mb-0 small lh-125 border-bottom border-gray"&amp;amp;amp;gt;

&amp;amp;amp;lt;div class="d-flex justify-content-between align-items-center w-100"&amp;amp;amp;gt;
                            &amp;amp;amp;lt;strong class="text-gray-dark"&amp;amp;amp;gt;{{item['id']}} - {{ item['item_name'] }}&amp;amp;amp;lt;/strong&amp;amp;amp;gt;

                            	&amp;amp;amp;lt;a href="{{ url_for('edit', id=item['id']) }}"&amp;amp;amp;gt;Edit&amp;amp;amp;lt;/a&amp;amp;amp;gt;

                            	&amp;amp;amp;lt;a href="{{ url_for('delete', id=item['id']) }}"&amp;amp;amp;gt;Delete&amp;amp;amp;lt;/a&amp;amp;amp;gt;


                        &amp;amp;amp;lt;span class="d-block"&amp;amp;amp;gt;{{ item['description'] }}&amp;amp;amp;lt;/span&amp;amp;amp;gt;


                {% endfor %}

As you’ll notice, we’re already binding our data from the back-end and we’ve prepared our href for the edit and delete.

Now place the following in your


@app.route('/edit/&amp;amp;amp;lt;int:id&amp;amp;amp;gt;', methods=('GET', 'POST'))
def edit(id):
    dbo = db.get_db()
    items = dbo.execute(
        'SELECT * FROM list'
    return render_template('index.html', items=items)

@app.route('/delete/&amp;amp;amp;lt;int:id&amp;amp;amp;gt;', methods=('GET', 'POST'))
def delete(id):
    dbo = db.get_db()
    items = dbo.execute(
        'SELECT * FROM list'
    return render_template('index.html', items=items)

We only placed this code for placeholder purposes. We’ll be modifying this in a short while. Let’s go back to our browser and check the results.


We have our data now displaying on the front-page. So once we add another data on the registration page, there’s more rows appearing on it. Now to make the edit and delete work


9. Editing and Deleting data

Let’s work on with the editing. On the, modify your edit function to these lines of code

9.1 Editing data

@app.route('/edit/&amp;amp;amp;lt;int:id&amp;amp;amp;gt;', methods=('GET', 'POST'))
def edit(id):
    if request.method == 'GET':
        dbo = db.get_db()
        item = dbo.execute(
            'SELECT * FROM list WHERE id = ?', (id,)
        return render_template('edit.html', item=item)

    elif request.method == 'POST':
        item_name = request.form['item_name']
        description = request.form['description']
        amount = request.form['amount']
        category = request.form['category']
        dbo = db.get_db()
        error = None

        if not item_name or not description or not amount or not category:
            error = 'You have incomplete fields. Kindly double-check.'

        if error is None:
                'UPDATE list SET item_name = ?, description = ?, amount = ?, category = ? WHERE id = ?',
                (item_name, description, amount, category, id)

            item = dbo.execute(
                'SELECT * FROM list WHERE id = ?', (id,)
            flash('Successfully updated item!')
            return render_template('edit.html', item=item)
            return render_template('edit.html', item=item)



What we’ve done is we’ve added mechanism for each HTTP request. I guess by now you’ve already got the point so I don’t need to explain further. You’ll notice we’ve changed the return file to edit.html and the SQL query to UPDATE on the POST request. Now let’s create a file called “edit.html“. Save it in the template folder then copy-paste all the contents of add.html. From there, modify the following:


&amp;amp;amp;lt;div class="mb-3"&amp;amp;amp;gt;
              &amp;amp;amp;lt;label for="description"&amp;amp;amp;gt;ID&amp;amp;amp;lt;/label&amp;amp;amp;gt;
              &amp;amp;amp;lt;input type="id" name="id" value="{{item['id']}}" class="form-control" id="id" disabled=""&amp;amp;amp;gt;


&amp;amp;amp;lt;div class="mb-3"&amp;amp;amp;gt;
              &amp;amp;amp;lt;label for="item_name"&amp;amp;amp;gt;Item name&amp;amp;amp;lt;/label&amp;amp;amp;gt;

&amp;amp;amp;lt;div class="input-group"&amp;amp;amp;gt;
                &amp;amp;amp;lt;input type="text" name="item_name" value="{{item['item_name']}}" class="form-control" required&amp;amp;amp;gt;

&amp;amp;amp;lt;div class="invalid-feedback" style="width: 100%;"&amp;amp;amp;gt;
                  Your item name is required.




&amp;amp;amp;lt;div class="mb-3"&amp;amp;amp;gt;
              &amp;amp;amp;lt;label for="description"&amp;amp;amp;gt;Description&amp;amp;amp;lt;/label&amp;amp;amp;gt;
              &amp;amp;amp;lt;input type="text" name="description" value="{{item['description']}}" class="form-control" id="description" required&amp;amp;amp;gt;


&amp;amp;amp;lt;div class="mb-3"&amp;amp;amp;gt;
              &amp;amp;amp;lt;label for="amount"&amp;amp;amp;gt;Amount&amp;amp;amp;lt;/label&amp;amp;amp;gt;
              &amp;amp;amp;lt;input type="text" name="amount" value="{{item['amount']}}" class="form-control" id="amount" required&amp;amp;amp;gt;

&amp;amp;amp;lt;div class="invalid-feedback"&amp;amp;amp;gt;
                Please enter your amount.



&amp;amp;amp;lt;div class="mb-3"&amp;amp;amp;gt;
              &amp;amp;amp;lt;label for="category"&amp;amp;amp;gt;Category&amp;amp;amp;lt;/span&amp;amp;amp;gt;&amp;amp;amp;lt;/label&amp;amp;amp;gt;
              &amp;amp;amp;lt;select name="category" value="{{item['category']}}"&amp;amp;amp;gt;
&amp;amp;amp;lt;option&amp;amp;amp;gt;Personal Care&amp;amp;amp;lt;/option&amp;amp;amp;gt;



We basically loaded our data coming from the db so the user doesn’t need to pre-fill the info. We’ve added an ID field so the user could be have more details. This is a disabled field so nobody can edit. Let’s go back to our browser and modify the following:

I have entered the following details and clicked submit as seen on the screenshot.


To make the front-page more intuitive, let’s add the amount code – ${{ item[‘amount’] }} in your index.html

We can now edit. For our last function, delete!

9.2 Deleting data

For delete, this should be a lot simpler than edit. On your, just copy the contents inside your edit function to keep things faster. Past them in your delete function, delete some codes and modify in which it looks like this:


@app.route('/delete/&amp;amp;amp;lt;int:id&amp;amp;amp;gt;', methods=('GET', 'POST'))
def delete(id):
    if request.method == 'GET':
        dbo = db.get_db()
        item = dbo.execute(
            'SELECT * FROM list WHERE id = ?', (id,)
        return render_template('delete.html', item=item)

    elif request.method == 'POST':
        dbo = db.get_db()
        error = None

        if not id:
            error = 'Item does no exist.'

        if error is None:
                'DELETE from list WHERE id = ?',

            items = dbo.execute(
                'SELECT * FROM list'

            return render_template('index.html', items=items)
            item = dbo.execute(
                'SELECT * FROM list WHERE id = ?', (id,)
            return render_template('delete.html', item=item)



The codes are just the same from add. Only modified the SQL query then deleted some validation since we don’t need them anymore. Just copy-paste add.html then past it on a new file called “delete.html“. Delete most of the stuff and make sure this is your end output:


It’s just a confirmation message asking if you want to continue deleting. If you submit, it shall redirect you back to the homepage. On your browser, go to your Fish row then click on delete. You should see this UI:

Click on submit and you should be redirected on the home page without that row anymore. Not that there are not confirmation messages this time. You’ll just know it’s deleted when you see it


Presto! We’re done with the basics! Let’s just clean up a few more things. Go to your master.html and modify your navbar and title to “My Grocery List”

Next, go to your index.html then change your headers to “Test App” and “Just a sample”

This should be your final home page overall

Alright! We’re finally done with the app! Now let’s deploy this!


10. Deploying your app using Heroku

Let’s keep this thing up so wherever you go, you can add something to your grocery list.


10.1 Setting up necessary files and configurations

Install gunicorn by typing pip install flask gunicorn

Gunicorn is a tool that boots up a server similar to what you do when you type “flask run” but in translation it becomes “gunicorn


Let’s create our requirements file by going to the terminal. On your project folder, type in pip freeze > requirements.txt and it should generate a text file. requirements.txt is a file that lists down all the libraries and dependencies installed on your project. This will be used by the remote server to determine what libraries are needed to be installed.


Next, login to Heroku by typing in heroku login

Had to hide my credentials for security reasons.


We’ll create a file called Procfile which will be used in the deployment server to know which file should be used for startup. Go back to your text editor, create a file called “Procfile” (without any extensions) then type the following:

web: gunicorn app:app


Next, let’s create a remote server where we’ll be placing the website. In your terminal, type in heroku create. It should create a random domain name (which can be changed later). By creating this in your terminal, this is already associated with your Heroku account and you should see it on your dashboard upon logging in.


10.2 Linking the remote server to your application

Now let’s link that server we create to our website. We’ll be using Git for linking and deployment.

On your project folder, type in git init on your terminal. It should initialize as a new git repository.

Note: If you’re using Mac, you might need Xcode. Click here for instructions

Next, we’ll link you Github to our Heroku repo. We’ll do that by typing heroku git:remote <name_of_the_created_app>

In my case it was fierce-forest-93644; Overall it should be heroku git:remote fierce-forest-93644. Apologies I had no screenshot of it 🙁


We’ll now commit all changes and push all of them to the Heroku server. In other words, this is the real deployment part!

From the command line, type in git add . and git commit -m “Deployment”. Git add (dot) states that all the files in this directory shall be staged for commit. Git commit is saving changes in your local to serve as a checkpoint of changes.

Note: The message will be lengthy so I’ll just shorten out the screenshot. This isn’t actually a good practice to include all files but we’re only doing it for the sake of the tutorial

Now for the last part, git push heroku master. This will now push all our commits to the server. It will now run the requirements.txt to see requirements and install all dependencies.


If all goes well, congratulations! You have your app up and running. If not, the error is likely coming from the requirements.txt as the library may not be compatible to the server or has missing dependencies (just like what happened to me now) which disallowed my push. If you’re push was all successful, no need to follow the steps below.


10.3 Fixing requirements.txt issues (optional if you had issues)


In order to remedy these, go to your requirements.txt then delete the library that was mentioned. Once deleted, do another git push heroku master. In this example I had to delete bonjour-py==0.3.

If another error persist, remove that library again on the requirements.txt, do a git add and commit again then redo the push.

Note: I’ve been doing that same exact process a lot of times ’till I finally got the sweet spot of my libraries. So in your case it might be possible too. But don’t worry, the next time you deploy you’ve cleaned up all unnecessary libraries.

After several attempts, it’s finally deployed!

This is what my requirements.txt looks like after reducing tons of libraries. Replicate at your own risk if your problem persists and this may be your last resort if your requirements.txt seems dirty already.


Here’s what it looks like in the browser.


As you can see it’s exactly the same as what we’ve did. You might wonder why the data is still up? It’s because we also uploaded our sqlite database. Remember? The one from the instance folder. Yup that’s where the data is stored and it felt like the same where you left off. You could try out the app and see for yourself.



All of these can be done in 30 mins. The article is long and it may not seem to be 30 mins but once you’re familiarized with the platform you can do it in fast pace! If you wish to deploy updates, you’ll have to add, commit, and push like what you’ve did.


Next steps

You could challenge yourself and carry over this app to improve it’s features. Some of which may not be limited to:

  • Adding validation
  • Proper error handler
  • Fixing the UI
  • Make a survey
  • A LOT!

For your reference, here’s the link to the full source code


Hope you guys enjoyed the tutorial!

I agree to have my personal information transfered to MailChimp ( more information )
Signup today and receive free updates straight in your inbox. I won't share or sell your email address 😀
I hate spam as much as you do so your email address will not be sold or shared with anyone else.


Leave a Reply

Your email address will not be published. Required fields are marked *