The Official Guide to Serverless Flask

Is it your first time using the Flask Microframework for Python and you're looking for a great option to host it? Or are you an experienced user hoping to move your Flask application into a low cost, pay-per-execution AWS Lambda environment? Either way, this guide should help you get started with the the best way to deploy a Flask application on AWS - by using the Serverless Framework.

In this guide, we will look at everything you need to know about using Flask, the Serverless Framework and AWS Lambda together. We'll talk about the upsides and downsides and give you several other resources to get more hands-on experience using all of these tools. If it's your first time hearing about AWS Lambda, you might want to check out our AWS Lambda Guide or look at some of our free courses and tutorials on serverless application development.


Table of Contents



What is Flask?

Flask one of the two most popular Python development frameworks because of it's simplicity, extensibility, and community. For the same reasons, the Serverless Framework is the most popular development tool for deploying serverless applications on Functions as a Service infrastructure like AWS Lambda.

Flask is an unopinionated web microframework for Python. This means rather than providing a heap of built-in functionality it offers the extensibility of adding in different tools to it when appropriate.



How does Flask work with the Serverless Framework?

The Serverless Framework can be used to deploy applications on several different platforms. The most common of these, and the focus of this guide, is AWS Lambda. In this guide, we'll use the Serverless Framework to deploy a Flask application as an AWS Lambda function sitting behind Amazon API Gateway. Here's a simplified version of how things work behind the scenes:

Architecture diagram showing the request flow from API Gateway to Lambda to Flask

First, the HTTP request is made from a frontend application or any other source. Then the API Gateway processes that HTTP request and transforms it into an event payload for AWS Lambda.

Inside of Lambda, the payload is processed by a Serverless Framework plugin and passed along to Flask.

Then, Flask handles the request using the same routing and logic you might otherwise expect from a Flask application and returns a response. The response goes back out through Lambda to API Gateway and is returned to the client making the HTTP request.

For a much more detailed overview, head down to the Getting Started section below.



What are the most common use cases for Servereless Flask Applications?

Flask is an incredibly flexible tool. Because of that, there are a lot of possibilities for what it can do and the most common use cases for Serverless Flask applications mirror those of AWS Lambda generally:

  1. Highly Elastic HTTP APIs
  2. Simple websites
  3. Data pipelines

Highly Elastic HTTP APIs.

Because you pay to use AWS Lambda only when it is processing an incoming request, your cost scales proportionately to your usage. Additionally, because AWS manages the underlying infrastructure for you, the application will scale up to meet the demands of your application.

Flask is particularly useful for creating HTTP APIs because it provides easy built-in ways to handling different API routes. Flask, and Python generally are also one of the most common programming languages for a variety of common serverless service vendors like Auth0, Stripe, Algolia and may others.

Simple Websites.

Flask can also be used to render and serve HTML pages. This can be a relatively easy way to get a website up and running that pre-renders HTML and delivers it to the browser.

However, when using Flask and AWS Lambda because you have some filesize limitations you may not be able to host websites over a certain size and may want to split large assets like images out to a service like Amazon S3.

As an alternative to this, you can also opt to use Amazon S3 Static Site hosting to store and serve your website files and something like this Serverless Finch plugin to deploy those files to S3 easily.

Data Pipelines.

Because of Flask's flexibility you can also use it as a thin middle layer between your incoming requests and routes and the backend data processing capabilities of something like numpy, scipy or other libraries. However, it's important to keep in mind some of the limitations of AWS Lambda such as the maximum function package size and the maximum disk space available to a Lambda function when running.

Benefits of using Flask and Serverless

So what are the benefits of using Flask and Serverless? Well, you'll be able to leverage many of the same benefits of AWS Lambda while still getting the Flask development experience. Here are some of the benefits that contrast best with other Flask development experiences.

Managed auto-scaling infrastructure.

If you've used Flask before, you might have had to spin up a virtual machine instance, install lots of prerequisites, configure networking, and more onerous tasks. Using Flask in AWS Lambda you don't have to do any of this and you still get the benefits of auto-scaling pay-per-execution infrastructure that serverless development provides. Even when you're using something like Elastic Beanstalk or Heroku you still have to think about scaling and capacity of your application.

Tight integration with other AWS products.

When using Flask with other environments like Heroku you might need to setup additional configuration and credentials to leverage services like Amazon S3, Amazon DynamoDB, Amazon Simple Queue Service (SQS) or other AWS services. When you run your application in AWS Lambda, you can assign an IAM role to your application that gives it permission to access these services. This can help supercharge your development process by giving you access to services and design patterns that will spare you development time and effort.

While you could get some of the same functionality from services like Amazon EC2 or Elastic Beanstalk, it's harder to replicate the event-driven nature of using Flask with AWS Lambda and Amazon API Gateway.

Manage API Endpoints in Flask

When you're developing a serverless HTTP API with lots of endpoints you may want to reuse a lot of the boilerplate code that allows it to run rather than duplicating it all over the place. For example, you could make sure that you're consistent in how you interact with something like DynamoDB, rather than reusing code everywhere.

Additionally, you can leverage Flask-related tools like Flask-RESTful or Python tools that help work with API data like Cerberus or Python JSON Schema.

Another benefit of doing this from inside of Flask, is that you're less likely to run into CloudFormation stack resource limitations. When you have a single serverless service with many discrete API endpoints and functions (rather than a larger single function), it may eventually generate more than 200 AWS resources in that CloudFormation stack and force you to split up the service.

And of course, you're also brining along the rest of the benefits of AWS Lambda. If you're curious about those, you can read our [AWS Lambda guide]((https://serverless.com/aws-lambda/) too!



Limitations of Flask and Serverless

Lambda Limitations

Flask apps running in AWS Lambda are subject to the same limitations as Lambda. Some of the most relevant restrictions for Flask applications because of this include:

  • A maximum execution duration with a maximum of 15 minutes or lower depending on your configuration
  • A maximum provisioned RAM of 3008 MB or lower depending on your configuration
  • A maximum compressed file size of 50MB and 250MB when unzipped - This means your entire Flask application, Python dependencies and and other included files must be limited to these amounts

Async Programming

Another potential limitation of Flask is that it may be harder to develop asynchronously. By default, Python code is synchronous and if you expect your application will need to deviate from this, you should look at something like Python's asyncio or consider writing an application in JavaScript with something like Express.js.

Bring Your Own Dependencies

Because Flask "unopinionated", it means that you need to provide the tools you need to interact with parts of your application, validation libraries, an ORM, form libraries or many other tools will need to be bundled with it.

This contrasts dramatically with other Python frameworks like Django, which bundle in tooling for user authentication, email, and database interactions. In the Flask world, it's not assumed your application will require any of these features, let alone modules to support all of them. This minimalist philosophy fits perfectly with the cloud based miroservice approached that characterizes serverless applications.

Rather than using a a built-in authentication module, you might add a third party tool like Auth0 or Amazon Cognito. For emails, you might rely on Amazon SES or Twilio. The database might be a managed SQL database like Amazon Aurora or a NoSQL service tool like Amazon DynamoDB. Flask can easily extend to work with these tools while at the same time providing an easy development experience for your Python projects.



Frequently asked questions (FAQ)

Is Flask open source? Yep! You can review the source code on GitHub here.

Can Flask Scale? Flask and AWS Lambda can scale very well to respond to requests. In terms of the scale of development, it's important to remember that there are hard limitations on the Lambda package size which implicates the number and size of Flask dependencies you use.

Can Flask interact with other AWS Services? Yes absolutely, when Flask is deployed in a Lambda Function it gets access to all the Identity and Access Management (IAM) permissions associated with that function. For example, if you want to handle objects inside of Amazon S3 you might use the Boto3 library to do so. Boto3 will then pick up permissions automatically from the AWS Lambda runtime. As long as you configure the sufficient permissions for your application it should work seamlessly.

Why not use Django? Well, there's nothing wrong with Django at all. In fact, there are plenty of people doing something similar with Django and AWS Lambda. However, Django's larger package size can make it more susceptible to hitting Lambda function size limitations. Additionally, because Django provides a lot of built-in functionality that will likely be left alone in favor of AWS services, it might not be the most effective use of disk space for a serverless application.



Getting started with Flask

In this portion of the guide, we'll look at how to create your very own Flask application using the Serverless Framework. We'll cover all the steps required to get you started with a Flask application inside of AWS Lambda. Keep in mind that I'll be mostly using commands that apply to Linux and Mac systems but I'll explain what they do so you can take the equivalent actions on other systems too.

Setup and Initial Requirements

In order to work with Flask and the Serverless Framework you'll need to make sure you have a few things setup:

  • Install Python 3 which should also install Python's package manager - pip
  • Install [Node.js] which comes with with the Node Package Manager, npm. We'll use this to get the Serverless Framework plugins you need for this project
  • Install Serverless Framework
  • Install the AWS CLI
  • Configure the AWS CLI
  • Install Docker This step may not always be necessary, but when you're working with some Python dependencies it is helpful to have this
  • (Optional) - Create a free tier Framework Pro account if you want automatic monitoring, debugging and alerting tools

After these setup steps, you'll be ready to create your application!

Creating Our `serverless.yml` File

The first step, will be to create a new project folder. Let's call this flaskapp. Inside the flaskapp directory, we'll need to create a few files starting with the serverless.yml file, which is used to configure your Serverless Framework application.

Commands to do this:

  • mkdir flaskapp
  • cd flaskapp
  • touch serverless.yml

Inside of serverless.yml, we'll need to include some configuration details for our application. I'll explain what each section does in a moment, but here's what the final file will look like if you'd like to copy and paste it:

org: myorg
app: helloapp
service: flask-api

provider:
  name: aws
  runtime: python3.7

functions:
  app:
    handler: wsgi_handler.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'

custom:
  wsgi:
    app: app.app
    pythonBin: python3 # Some systems with Python3 may require this
    packRequirements: false
  pythonRequirements:
    dockerizePip: non-linux

plugins:
  - serverless-wsgi
  - serverless-python-requirements

Org, App and Service

org: myorg
app: helloapp
service: flask-api

The org and app here allow us to connect our service to Serverless Framework Pro for automatic monitoring and debugging, alerting, CI/CD, safeguards and other Framework Pro features. Organizations are the highest-level concept that allow you to manage teams, deployment profiles, safeguards and other configuration. The applications inside of them are logical groupings for every service you create.

The Provider

provider:
  name: aws
  runtime: python3.7

In this section, you specify the cloud provider, Amazon Web Services in this case, and then the AWS Lambda language runtime you'd like to use. You're welcome to use other versions of Python 3, however as of the writing of this guide I tested this code with Python 3.7.

Functions and Events

functions:
  app:
    handler: wsgi_handler.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'

When working with AWS Lambda you create Lambda Functions. You can configure these functions with varying events that trigger them. In this case, we create a function called app. This function has a handler that determines where we look for the Python code we'd like to run when the Lambda Function is triggered. In this case, we're going to be relying on the serverless-wsgi plugin later on to help us work with Flask. It will translate HTTP requests from API Gateway into the correct format to be passed along to Flask. On the way back, it will also handle returning the requests back over to API Gateway.

In other contexts, we might be able to rename this handler something else, but in the context of this plugin, it expects us to have the handler of wsgi_handler.handler so we'll stick with that.

The events section is creating two catch-all Amazon API Gateway endpoints and events. Essentially, this means that all requests routed through API Gateway will be passed along to the serverless-wsgi plugin and sent to Flask. From there, Flask will handle any and all application routes. For example, when an HTTP request is sent to https://our-api-endpoint.com/customer/id123, Flask will take the request and process it in accordance with whatever the /customer/id123 route specifies in our Flask app. Don't worry, we'll look at this more later.

Plugins and Configuration

custom:
  wsgi:
    app: app.app
    pythonBin: python3 # Some systems with Python3 may require this
    packRequirements: false
  pythonRequirements:
    dockerizePip: non-linux

plugins:
  - serverless-wsgi
  - serverless-python-requirements

In the next part of the serverless.yml file there are two top-level sections. The custom section contains custom configuration for the two plugins we're using in this project. The plugins section includes the names of those two plugins so the Serverless Framework can hook into the functionality they provide.

The serverless-python-requirements plugin will be used in order to bundle Flask and all other Python dependencies you have for the application. It's configuration is in the pythonRequirements section. The way you use this plugin depends on your operating system. I've included the configuration for Mac users with the non-linux option that may also work on other systems. However, if you face any issues I'd suggest reviewing the configuration options on the Plugin's GitHub. In order to make sure this plugin installs your requirements, you'll need to create a requirements.txt file containing any dependencies you need for your project. We'll come back to this in a bit.

The serverless-wsgi plugin allows us to use Flask and other Python web frameworks inside of AWS Lambda. If you're curious, you can read more about it here. It's going to allow us to run our Flask application locally and also help us get our Flask application configured in AWS Lambda. In order to do this, we have the wsgi section of the custom block of YAML code above.

Inside of the wsgi configuration, we can configure how the plugin should call Python in order to spin up a local instance of our application using pythonBin. In this case, my operating system has the python3 command setup to refer to the version of Python I want. However you could also specify a particular version using something like: pythonBin: python3.7.

The packRequirements section is another option for helping us bundle our Python requirements together. However, we'll be using the serverless-python-requirements plugin mentioned above in order to do this so we can leave this as false.

The app section above these two options lets us specify where the Flask code will live and the location of the Flask app variable inside that file. Using the syntax of app.app will point to a Python file called app.py and the app variable inside of that file. This will all be relative to the serverless.yml file so we'll need to make sure to include an app.py file. Let's create that now!

Creating Our Flask App in app.py

The next file you'll need to create is app.py. This will serve as our main entry point for our Flask application. You can run touch app.py to create the file. Then add this code inside of it:

from flask import Flask
app = Flask(__name__)

@app.route('/hello/<name>')
def hello(name):
    return 'Hello ' + name + '!'

The first two lines will import the Flask library and then create a Flask variable app. In Python __name__ is a special variable that tells us if the file is being run directly or imported from another file. Essentially it let's us tell Flask where app.py is located to setup some paths.

After that, we'll create our first route to handle traffic when requests are made to a path starting with /hello/something. The @ syntax at the start of a line in Python is called a decorator, and it allows us to augment the functionality of the function defined directly below it. If you'd like a more detailed explanation of decorators, this is a pretty good overview. Essentially, this decorator allows us to setup a route that we will respond to with the function below it. As part of the @app.route decorator we use the <> syntax for <name>. This allows us to create a variable input as part of the path. We can then pass this along to the hello() function on the next line as an input.

Essentially, the last two lines create the function hello that we use to create a response for any requests to the path. We'll see how this works in a moment, but first we actually need to install Flask, and our Serverless Framework plugins.

Python Dependencies in `requirements.txt`

At this point, we can add a requirements.txt file. On Mac/Linux you can use touch requirements.txt and then add the Flask dependency to that file with echo Flask > requirements.txt. The file will contain our Python dependencies that we plan to use in AWS Lambda, for right now it just looks like this:

Flask

This simple requirements.txt file will be used by the serverless-python-requirements plugin in order to install the proper dependencies for us. So let's setup our plugins now!

Installing Out Serverless Framework Plugins with `npm`

In order to install both of the Serverless Framework Plugins we'll be using, we'll need to rely on npm. We can run these commands to install both plugins in our repository:

  • npm install serverless-wsgi
  • npm install serverless-python-requirements

After you run both of these plugins we should be able to deploy our Flask application!

Deploying and Testing Our Flask App

The final step, is to run serverless deploy. When you do that, you should see an output that starts off something like this:

Output part one, with the Serverless Python Requirements

The first few lines of output describe what our plugins are doing in order to properly bundle up our code, Flask, and any other dependencies.

Then, the Safeguards Results: section shows us the results of any configured Framework Pro Safeguards.

Safeguard results section

Fortunately, all mine passed and the deployment was successful. You'll only see these if you're using the org and app values from your Framework Pro account.

Finally, when the deployment finishes, we can see that the Service Information section contains an API Gateway endpoint URL.

Service Information

My endpoint URL looks like this, but yours will have a different random API id (the luyyqbqp6b in mine) and may have a different region depending on where you deploy it: https://luyyqbqp6b.execute-api.us-east-1.amazonaws.com/dev.

With this URL we can test the app by going to https://luyyqbqp6b.execute-api.us-east-1.amazonaws.com/dev/hello/fernando:

Displayed results of visiting the URL

Nice work! We've deployed our first Serverless Flask application on AWS. If we included an org and app value in serverless.yml we can then go into our Framework Pro account to monitor it. At the bottom of our serverless deploy there was a section that looked like this: x

Serverless: Successfully published your service to the Serverless Dashboard: https://dashboard.serverless.com/tenants/fernando/applications/helloapp/services/flask-api/stage/dev/region/us-east-1

Just click on the link there, sign in, and you can review your applications! If you want to get to the logs you can either click through to your app and service or just add a /overview to the end of the URL if it shows up like I've included above.

The overview view in the Dashboard

From the overview tab, you can review the recent requests to our Flask API. You can also get a more detailed view by clicking the "explorer" section:

The Explorer view in the Dashboard

In this section you can review the requests by endpoint or function invocation and dig into the logs for each of them.



Adding Other AWS Services

So now that we've got our Flask Application running in AWS, what if we wanted to start leveraging AWS services? Well, it's actually pretty easy! Let's look at how we can turn our Flask application to text people a nice message.

Adding Permissions to Our Application

The first step of adding in permissions to our application is to add permissions in to our serverless.yml file that will make sure the Lambda Function we deploy it into will be able to access the different AWS services we want to work with. One way to do this is to add a new iamRoleStatements section in the provider section of your serverless.yml file:

provider:
  name: aws
  runtime: python3.7
  iamRoleStatements:
  - Effect: Allow
    Action: "sns:Publish"
    Resource: "*"

In this section, we'll add an IAM policy to be applied to our Lambda Function. The effect of "Allow" allows some AWS API action. The Action section determines which action or actions. And the final section determines which resource the action can be taken on. In this case, we're allowing "*" for any resource. This is a very permissive policy that would allow us to publish to any SNS Topic. If you'd like to narrow it down to just publishing to phone numbers you could replace the Resource line with this: NotResource: "arn:aws:sns:*:*:*". This is a less-used IAM Policy syntax that allows us to specify all the resources that the action is not allowed to be taken on. Because sns:Publish only works on SNS Resources and phone numbers this effectively just allows it to be used on Phone numbers for this service.

Now that our application has the permissions it needs, let's update our code!

Updating our Flask App

In app.py once again, let's change our code a bit. At the top, let's bring in boto3, the AWS SDK for Python.

import boto3
from flask import Flask
app = Flask(__name__)

@app.route('/hello/<phone_number>')
def hello(phone_number):
    sns = boto3.client('sns')
    sns.publish(
        PhoneNumber=phone_number,
        Message=(
            "Hello! Someone just wanted you to know that they're "
            "thinking about you and you rock! - Sent from flaskapp"
        )
    )
    return f'Thanks for stopping by, we are sending {phone_number} a nice text now!'

Let's also change up our app route to have a phone number as the path variable now. Inside of that route, we can use boto3 to create a Simple Notification Service Client and then run sns.publish(). In this case, we're publishing a text message out to the phone number in the path.

Finally, we're returning a message to whoever loaded the page, letting them know we sent that number a nice message. When you finish updating the code, run serverless deploy again and test out the endpoint with your phone number. Keep in mind, you'll need to add a + and the country code at the start of your phone number. Here's an example:

The message sent page

And, I got a nice message sent to me!

The message sent page

Now that we have some AWS services working with our Flask App, what happens as we start to develop it more? Let's look at how we can refactor our Flask app to make it more maintainable.

Restructuring Our Flask Application

First, let's review what's in our directory so far:

The tree of our flaskapp

While this looks good now, what happens when we add more functionality to our app? We'll want to move functionality out of app.py into other files. So let's try this ourselves.

Let's make a new directory called messages

  • mkdir messages

Then let's go into that directory and create a new file called send.py

  • cd messages
  • touch send.py

Inside send.py let's create two functions compliment() and greeting():

# send.py
import boto3

sns = boto3.client('sns')


def compliment(phone_number):
    sns.publish(
        PhoneNumber=phone_number,
        Message=("Hey! You're really cool!")
    )


def greeting(phone_number):
    sns.publish(
        PhoneNumber=phone_number,
        Message=("Hello and good morning!")
    )

In the long run, it's pretty likely we'll want to refactor our code into different directories, files and functions like this to help us keep the code a little easier to maintain. So how do we make use of this?

In app.py we can bring in these functions from messages/send.py. But we have to do one more thing first! We need to create a special __init__.py file in the messages folder - that's two underscores on both sides! This will tell the Python language to treat that directory like something we can import from. You can do this simply by running touch __init__.py in the messages directory.

Using `send.py` in `app.py`

Now we should be able to go back to app.py and change our code to this:

from messages import send
from flask import Flask
app = Flask(__name__)

@app.route('/compliment/<phone_number>')
def compliment(phone_number):
    send.compliment(phone_number)
    return f'Thanks for stopping by, we are sending {phone_number} a compliment now!'

@app.route('/greeting/<phone_number>')
def greeting(phone_number):
    send.greeting(phone_number)
    return f'Thanks for stopping by, we are sending {phone_number} a greeting now!'

With this update, let's try running serverless deploy again. If you see an error that says this:

This command can only be run in a Serverless service directory.

It's because you need to change directories up to the top-level directory with serverless.yml in it first. Our new project folder should look like this:

The latest tree of our flaskapp

With this new version of our application we can make a request to two different endpoints:

  • https://luyyqbqp6b.execute-api.us-east-1.amazonaws.com/dev/compliment/+15556667777
  • https://luyyqbqp6b.execute-api.us-east-1.amazonaws.com/dev/greeting/+15556667777

These will each generate unique responses and send unique text messages!

Running Our Flask Application Locally

Now, we've done a decent bit of development thus far, but what if we don't quite want to deploy into the cloud right away? Let's look at how we could do development on our application locally with serverless-wsgi.

First, we need to get our local Python dependencies setup. To install Flask and other Python dependencies, I suggest using a Python 3 tool called venv to keep your project dependencies separate from your system dependencies.

To use venv for this project, simply run python3 -m venv venv from the top level directory. This should create a new folder inside your project called venv.

This folder contains an entire separate installation of Python, pip, and will house all your project dependencies. You'll want to leave this folder out of your source code and eventually exclude it from your Lambda Function package too. We'll do this in the Optimizations and Cleanup section.

After you have the venv folder created, you should be able to activate it with one of these commands:

  • source venv/bin/activate when using bash or zsh (for most Mac and Linux users)
  • venv\Scripts\Activate.ps1 for PowerShell
  • venv\Scripts\activate.bat for cmd.exe

If you need more help with venv you can always look at the documentation here.When the virtual environment is activated you should see your command prompt change. Usually you will see a (venv) added before your prompt like this: (venv) $.

Now we need to install Flask in our Virtual environment, so with it activated we can run pip install -r requirements.txt to install everything inside in requirements.txt, which right now is just Flask.

But wait a minute, we didn't include boto3 in our requirements.txt file. How did our Lambda code work without us installing it?

Well, AWS Lambda already has the AWS SDKs available for us in the Lambda runtime. When we do local development we'll need to install it into the venv environment first. With your venv activated, you can do this with pip install boto3.

From there, you should have all the dependencies you need for local development. Next, run serverless wsgi serve.

You should see something like this:

Serverless: Using Python specified in "pythonBin": python3
 * Running on http://localhost:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 216-299-195

This shows you that the application is up and running locally on localhost. Open up the localhost link along with the port number (5000 in this case) in your web browser. You'll probably see an error message that says:

"Not Found The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."

That's because you haven't defined the root / resource and Flask doesn't know what to do. If you'd like to add that now, you can update your app.py file to include a route for that path like this:

from messages import send
from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello homepage!'

@app.route('/compliment/<phone_number>')
def compliment(phone_number):
    send.compliment(phone_number)
    return f'Thanks for stopping by, we are sending {phone_number} a compliment now!'

@app.route('/greeting/<phone_number>')
def greeting(phone_number):
    send.greeting(phone_number)
    return f'Thanks for stopping by, we are sending {phone_number} a greeting now!'

After you save, serverless-wsgi should display a message like this:

 * Detected change in '/Users/fernandomedinacorey/Desktop/flaskapp/app.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 216-299-195

When it detects a change it should refresh the application and you can try loading the page again. Now you should see this text appear: Hello homepage!

Now you're all setup with local development too! One important thing to keep in mind is that your application running locally will still be interacting with AWS services deployed in the cloud. So you may need to add some additional code to keep things separate.

In general, we suggest that you do your development in the cloud itself, as it can be very difficult to emulate AWS services like SNS or DynamoDB locally and trying to can lead to discrepancies between local environments and how the cloud actually performs. However, it can be nice to make a few changes, see them updated immediately, and then do a deployment with serverless deploy.

Optimizations and Cleanup

Now, let's do a few important optimizations and cleanup steps before we finish.

Cleaning Up Our Deployment Package

When we deploy our application, we stuff everything into a single zip file that gets uploaded to AWS Lambda. By default, that includes everything in the directory with your service. Because of that, we risk including a lot of extra stuff we don't need.

The first thing we should remove from the package is our venv directory. This is because we are using serverless-python-requirements to bundle up our requirements into the Lambda function package for us.

Also, because we're working with Python we don't need to bundle in the node_modules directory.

To remove both of these from our package, we can add a few lines of configuration to the bottom of our serverless.yml file:

package:
  exclude:
    - node_modules/**
    - venv/**

Adding these four lines to exclude node_modules and venv made my package size drop 18 MB!

Before: The latest tree of our flaskapp

After: The latest tree of our flaskapp

This can be a critically important step if you're getting close to the total Lambda function package size limitations and need to cut some of the things you don't need in the package.

Cleaning Up Our Source Code

If you're using git to version control your environment, you should also exclude the venv and node_modules folders from your source control. Both of those should be recreated by developers on their own systems to prevent a range of potential bugs and conflicts.

Links and references

I hope you now feel confident building out your own Flask applications using the Serverless Framework and AWS Lambda. By now, you've given yourself a great start! If you want to learn more about using Flask, Serverless, or other concepts I mentioned check out the links below for more information, and different guides.

New to serverless?

To get started, pop open your terminal & run:

npm install serverless -g