zappa
Zappa
Python

Serverless Python

Last updated Jul 7, 2026
3.7k
Stars
389
Forks
17
Issues
0
Stars/day
Attention Score
81
Language breakdown
Python 99.7%
Makefile 0.3%
Shell 0.0%
โ–ธ Files click to expand
README

Zappa Rocks!

Zappa - Serverless Python

CI Coverage PyPI Slack

- Minimal Configs - CLI Commands - Limitations and Constraints - Running the Initial Setup / Settings - Alternative: Generating Settings via CLI - Nested JSON Configurations - Initial Deployments - Updates - Docker Workflows - Settings that should NOT be used with Docker deployments - Rollback - Scheduling - Advanced Scheduling - Multiple Expressions - Disabled Event - EventBridge Rule Naming - Undeploy - Package - How Zappa Makes Packages - Template - Status - Tailing Logs - Remote Function Invocation - Django Management Commands - SSL Certification - Deploying to a Domain With AWS Certificate Manager - Deploying to a Domain With a Let's Encrypt Certificate (DNS Auth) - Deploying to a Domain With a Let's Encrypt Certificate (HTTP Auth) - Deploying to a Domain With Your Own SSL Certs - Catching Exceptions - Task Sources - Direct Invocation - Remote Invocations - Restrictions - Running Tasks in a VPC - Responses - YAML Settings - Keeping The Server Warm - Serving Static Files / Binary Uploads - Enabling CORS - Large Projects - Enabling Bash Completion - Enabling Secure Endpoints on API Gateway - API Key - IAM Policy - API Gateway Lambda Authorizers - Cognito User Pool Authorizer - API Gateway Resource Policy - Setting Environment Variables - Local Environment Variables - Remote AWS Environment Variables - Remote Environment Variables - Remote Environment Variables (via an S3 file) - API Gateway Context Variables - Catching Unhandled Exceptions - Using Custom AWS IAM Roles and Policies - Custom AWS IAM Roles and Policies for Deployment - Custom AWS IAM Roles and Policies for Execution - AWS X-Ray - Globally Available Server-less Architectures - Raising AWS Service Limits - Dead Letter Queues - Elastic File System (EFS) - Basic Configuration - Configuration Options - Security Group Configuration - Accessing EFS in Your Code - Notes - Unique Package ID - Application Load Balancer Event Source - ASGI Support - Setting Up a FastAPI App - The apptype Setting - Starlette Example - Quart Example - Binary Support with ASGI - ASGI Internals - ASGI Limitations - WebSocket Support - Using Decorators - Using a Base Class - Sending Messages to Clients - How It Works - Endpoint Configuration - Example Private API Gateway configuration - Cold Starts (Experimental) - Lambda Test Console Usage - rawcommand - manage - Using a Local Repo

About

Zappa Slides

In a hurry? Click to see (now slightly out-dated) slides from Serverless SF!

Zappa builds and deploys server-less, event-driven Python applications (including, but not limited to, WSGI and ASGI web apps) on AWS Lambda + API Gateway. Think of it as "serverless" web hosting for your Python apps. That means infinite scaling, zero downtime, zero maintenance - and at a fraction of the cost of your current deployments!

If you've got a Python web app (including Django, Flask, FastAPI, and Starlette apps), it's as easy as:

$ pip install zappa
$ zappa init
$ zappa deploy

and now you're server-less!

What do you mean "serverless"?

Okay, so there still is a server - but it only has a 40 millisecond life cycle! Serverless in this case means "without any permanent infrastructure."

With a traditional HTTP server, the server is online 24/7, processing requests one by one as they come in. If the queue of incoming requests grows too large, some requests will time out. With Zappa, each request is given its own virtual HTTP "server" by Amazon API Gateway. AWS handles the horizontal scaling automatically, so no requests ever time out. Each request then calls your application from a memory cache in AWS Lambda and returns the response via Python's WSGI interface. After your app returns, the "server" dies.

With Zappa you only pay for the milliseconds of server time that you use, so it's many orders of magnitude cheaper than VPS/PaaS hosts like Linode or Heroku - and in most cases, it's completely free. Plus, there's no need to worry about load balancing or keeping servers online ever again.

It's great for deploying serverless microservices with frameworks like Flask and Bottle, and for hosting larger web apps and CMSes with Django. Zappa also supports ASGI frameworks like FastAPI, Starlette, and Quart โ€” deploy async Python apps to Lambda with the same ease. You can use any WSGI or ASGI-compatible app you like! You probably don't need to change your existing applications to use it, and you're not locked into using it.

Zappa also lets you build hybrid event-driven applications with free SSL certificates, global app deployment, API access management, automatic security policy generation, precompiled C-extensions, auto keep-warms, and oversized Lambda packages.

Zappa Demo Gif

Quick Reference

Minimal Configs

Flask / Bottle (WSGI):

{
    "dev": {
        "appfunction": "yourmodule.app",
        "s3_bucket": "your-s3-bucket"
    }
}

Django:

{
    "dev": {
        "djangosettings": "yourproject.settings",
        "s3_bucket": "your-s3-bucket"
    }
}

FastAPI / Starlette / Quart (ASGI):

{
    "dev": {
        "appfunction": "yourmodule.app",
        "app_type": "asgi",
        "s3_bucket": "your-s3-bucket"
    }
}

CLI Commands

| Command | Description | |---|---| | zappa init | Interactive setup, generates zappa_settings.json | | zappa settings --stage <stage> | Generate settings via CLI (non-interactive) | | zappa deploy <stage> | First deployment to a stage | | zappa update <stage> | Push code changes without touching API Gateway routes | | zappa undeploy <stage> | Remove API Gateway and Lambda function | | zappa rollback <stage> -n <N> | Roll back N versions | | zappa schedule <stage> | Register scheduled events and event sources | | zappa unschedule <stage> | Remove scheduled event rules | | zappa package <stage> | Build deployment package without deploying | | zappa template <stage> | Generate API Gateway CloudFormation template | | zappa status <stage> | Show deployment status and event schedules | | zappa tail <stage> | Stream CloudWatch logs | | zappa invoke <stage> <func> | Execute a function remotely | | zappa manage <stage> <cmd> | Run Django management command | | zappa certify | Set up SSL certificate for custom domain |

Limitations and Constraints

| Constraint | Detail | |---|---| | Python versions | 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 | | Package size | 50MB zip limit; use slim_handler: true for larger projects | | Lambda timeout | Default 30s, max 900s; API Gateway hard-limits at 30s (use ALB for longer) | | Concurrent executions | AWS default 1000; request increase via support ticket | | Virtual environment | Zappa must be installed in a venv; venv name must differ from project name | | Default IAM policy | Overly permissive; customize for production | | Event function naming | Pattern ^[._A-Za-z0-9]{0,63}$ โ€” no hyphens allowed | | Async task args | Must be JSON-serializable, under 256K | | ASGI limitations | No WebSocket via ASGI, no lifespan protocol, no streaming responses | | Static files | Not designed for static assets; use S3 + CloudFront | | VPC internet access | Lambda in VPC requires NAT gateway for internet access |

Installation and Configuration

Before you begin, make sure you are running Python 3.9/3.10/3.11/3.12/3.13/3.14 and you have a valid AWS account and your AWS credentials file is properly installed._

Zappa can easily be installed through pip, like so:

$ pip install zappa

Please note that Zappa must be installed into your project's virtual environment. The virtual environment name should not be the same as the Zappa project name, as this may cause errors.

(If you use pyenv and love to manage virtualenvs with pyenv-virtualenv, you just have to call pyenv local [yourvenvname] and it's ready. Conda users should comment here.)_

Next, you'll need to define your local and server-side settings.

Running the Initial Setup / Settings

Zappa can automatically set up your deployment settings for you with the init command:

$ zappa init

This will automatically detect your application type (Flask/Django/FastAPI/Starlette - Pyramid users see here) and help you define your deployment configuration settings. Once you finish initialization, you'll have a file named zappasettings.json in your project directory defining your basic deployment settings. It will probably look something like this for most WSGI apps:

{
    // The name of your stage
    "dev": {
        // The name of your S3 bucket
        "s3_bucket": "lambda",

// The modular python path to your WSGI application function. // In Flask and Bottle, this is your 'app' object. // Flask (your_module.py): // app = Flask() // Bottle (your_module.py): // app = bottle.default_app() "appfunction": "yourmodule.app" } }

or for Django:

{
    "dev": { // The name of your stage
       "s3_bucket": "lambda", // The name of your S3 bucket
       "djangosettings": "yourproject.settings" // The python path to your Django settings.
    }
}

or for ASGI apps (FastAPI, Starlette, Quart):

{
    "dev": {
        "s3_bucket": "lambda",
        "appfunction": "yourmodule.app",
        "app_type": "asgi"
    }
}

See the ASGI Support section for details.

Psst: If you're deploying a Django application with Zappa for the first time, you might want to read Edgar Roman's Django Zappa Guide._

You can define as many stages as your like - we recommend having dev, staging, and production.

Alternative: Generating Settings via CLI

Instead of using the interactive init command, you can also generate your zappa_settings.json programmatically using the settings command with environment variables and command-line arguments:

$ zappa settings --stage dev

This generates a basic settings file with defaults. You can customize it using --config arguments or ZAPPA_ environment variables:

Using command-line arguments
$ zappa settings --stage production \
    --config project_name=myapp \
    --config memory_size=1024 \
    --config timeout_seconds=60
Using environment variables
$ export ZAPPAPROJECTNAME=myapp
$ export ZAPPAMEMORYSIZE=1024
$ zappa settings --stage production
Command-line arguments override environment variables
$ export ZAPPAMEMORYSIZE=512
$ zappa settings --config memory_size=2048  # Uses 2048, not 512

Nested JSON Configurations

The settings command supports complex nested JSON structures for advanced configurations like CORS options, VPC settings, and environment variables:

Configure CORS with nested JSON
$ zappa settings --stage production \
    --config 'cors_options={"allowedOrigins":["*"],"allowedMethods":["GET","POST","PUT"]}'
Configure VPC settings
$ zappa settings --stage production \
    --config 'vpc_config={"SubnetIds":["subnet-123","subnet-456"],"SecurityGroupIds":["sg-789"]}'
Configure environment variables
$ zappa settings --stage production \
    --config 'environmentvariables={"DATABASEURL":"postgres://...","API_KEY":"secret"}'
Configure Lambda layers
$ zappa settings --stage production \
    --config 'layers=["arn:aws:lambda:us-east-1:123:layer:mylayer:1","arn:aws:lambda:us-east-1:123:layer:another:2"]'

You can mix primitive values with complex nested structures:

$ zappa settings --stage production \
    --config project_name=myapp \
    --config memory_size=1024 \
    --config binary_support=true \
    --config 'cors_options={"allowedOrigins":["https://example.com"]}' \
    --config 'environmentvariables={"DBHOST":"localhost","DB_PORT":"5432"}'

The same nested JSON syntax works with environment variables:

$ export ZAPPACORSOPTI
$ export ZAPPAVPCC
$ zappa settings --stage production

Now, you're ready to deploy!

Basic Usage

Initial Deployments

Once your settings are configured, you can package and deploy your application to a stage called "production" with a single command:

$ zappa deploy production Deploying.. Your application is now live at: https://7k6anj0k99.execute-api.us-east-1.amazonaws.com/production

And now your app is live!

To explain what's going on, when you call deploy, Zappa will automatically package up your application and local virtual environment into a Lambda-compatible archive, replace any dependencies with versions with wheels compatible with lambda, set up the function handler and necessary WSGI Middleware, upload the archive to S3, create and manage the necessary Amazon IAM policies and roles, register it as a new Lambda function, create a new API Gateway resource, create WSGI-compatible routes for it, link it to the new Lambda function, and finally delete the archive from your S3 bucket.

Be aware that the default IAM role and policy created for executing Lambda applies a liberal set of permissions. These are most likely not appropriate for production deployment of important applications. See the section Custom AWS IAM Roles and Policies for Execution for more detail.

Updates

If your application has already been deployed and you only need to upload new Python code, but not touch the underlying routes, you can simply:

$ zappa update production Updating.. Your application is now live at: https://7k6anj0k99.execute-api.us-east-1.amazonaws.com/production

This creates a new archive, uploads it to S3 and updates the Lambda function to use the new code, but doesn't touch the API Gateway routes.

Docker Workflows

In version 0.53.0, support was added to deploy & update Lambda functions using Docker.

You can specify an ECR image using the --docker-image-uri option to the zappa command on deploy and update. Zappa expects that the image is built and pushed to a Amazon ECR repository.

Deploy Example:

$ zappa deploy --docker-image-uri {AWS ACCOUNT ID}.dkr.ecr.{REGION}.amazonaws.com/{REPOSITORY NAME}:latest

Update Example:

$ zappa update --docker-image-uri {AWS ACCOUNT ID}.dkr.ecr.{REGION}.amazonaws.com/{REPOSITORY NAME}:latest

Refer to the blog post for more details about how to leverage this functionality, and when you may want to.

Settings that should NOT be used with Docker deployments

When deploying with --docker-image-uri, the Docker image is responsible for bundling your application code and runtime. A few zappa_settings keys only make sense for zip-based deployments and will cause problems if left enabled for a Docker deployment:

  • slimhandler: This option splits the package into a slim handler and a separate project archive uploaded to S3. When enabled, Zappa writes an ARCHIVEPATH into the generated zappasettings.py, which makes the Lambda handler attempt to download the project archive from S3 at cold start and overlay it on your container's code. With a Docker deployment this either loads stale code from a previous zip deploy, or fails entirely if the archive is missing. Do not set slimhandler for Docker deployments. See issue #1341.
  • runtime: The Python runtime is determined by the Docker image, so this value is ignored for Docker deployments.
Running zappa deploy, zappa update, or zappa save-python-settings-file with a Docker-targeted configuration will now fail fast when any incompatible setting above is detected. Undeploying a stage that previously used slimhandler will also remove the leftover current_project.tar.gz archive from the configured S3 bucket.

If you are using a custom Docker image for your Lambda runtime (e.g. if you want to use a newer version of Python that is not yet supported by Lambda out of the box) and you would like to bypass the Python version check, you can set an environment variable to do so:

$ export ZAPPARUNNINGIN_DOCKER=True

You can also add this to your Dockerfile like this:

ENV ZAPPARUNNINGIN_DOCKER=True

Rollback

You can also rollback the deployed code to a previous version by supplying the number of revisions to return to. For instance, to rollback to the version deployed 3 versions ago:

$ zappa rollback production -n 3

Scheduling

Zappa can be used to easily schedule functions to occur on regular intervals. This provides a much nicer, maintenance-free alternative to Celery! These functions will be packaged and deployed along with your app_function and called from the handler automatically. Just list your functions and the expression to schedule them using cron or rate syntax in your zappasettings.json file:

Note: The function value must match the pattern ^[._A-Za-z0-9]{0,63}$ โ€” only letters, digits, dots, and underscores are allowed. Hyphens are not permitted. See EventBridge Rule Naming for details.

{
    "production": {
       ...
       "events": [{
           "function": "yourmodule.yourfunction", // The function to execute
           "expression": "rate(1 minute)" // When to execute it (in cron or rate format)
       }],
       ...
    }
}

And then:

$ zappa schedule production

And now your function will execute every minute!

If you want to cancel these, you can simply use the unschedule command:

$ zappa unschedule production

And now your scheduled event rules are deleted.

See the example for more details.

Advanced Scheduling

Multiple Expressions

Sometimes a function needs multiple expressions to describe its schedule. To set multiple expressions, simply list your functions, and the list of expressions to schedule them using cron or rate syntax in your zappasettings.json file:

{
    "production": {
       ...
       "events": [{
           "function": "yourmodule.yourfunction", // The function to execute
           "expressions": ["cron(0 20-23 ?  SUN-THU )", "cron(0 0-8 ?  MON-FRI )"] // When to execute it (in cron or rate format)
       }],
       ...
    }
}

This can be used to deal with issues arising from the UTC timezone crossing midnight during business hours in your local timezone.

It should be noted that overlapping expressions will not throw a warning, and should be checked for, to prevent duplicate triggering of functions.

Disabled Event

Sometimes an event should be scheduled, yet disabled. For example, perhaps an event should only run in your production environment, but not sandbox. You may still want to deploy it to sandbox to ensure there is no issue with your expression(s) before deploying to production.

In this case, you can disable it from running by setting enabled to false in the event definition:

{
    "sandbox": {
       ...
       "events": [{
           "function": "yourmodule.yourfunction", // The function to execute
           "expression": "rate(1 minute)", // When to execute it (in cron or rate format)
           "enabled": false
       }],
       ...
    }
}
EventBridge Rule Naming

Zappa creates EventBridge (formerly CloudWatch Events) rules for each scheduled event. The rule name encodes which Python function to execute, so the naming format matters.

How it works: The rule name is built as {lambda_name}-{function}. When the scheduled event fires, Zappa's handler extracts the function to call by splitting the rule name on - and taking the last segment:

whole_function = event["resources"][0].split("/")[-1].split("-")[-1]

For example, with lambda name my-app-prod and function tasks.cleanup:

  • Rule name: my-app-prod-tasks.cleanup
  • Handler extracts: tasks.cleanup (last segment after -)
  • Zappa imports and executes tasks.cleanup
Restrictions on function:

| Constraint | Value | |---|---| | Allowed characters | Letters, digits, dots (.), underscores (_) | | Pattern | ^[._A-Za-z0-9]{0,63}$ | | Max length | 63 characters | | Hyphens | Forbidden โ€” would break the - split extraction |

If the function were my-tasks.cleanup, the handler would extract only cleanup (the segment after the last -), and the import would fail.

The rule name must always end with the function path as the last hyphen-delimited segment. If it doesn't, the handler silently skips execution โ€” the event fires but nothing happens. The name setting field inserts a prefix into the rule name but does not change this requirement. The rule name becomes {lambda_name}-{name}-{function}, and the handler still extracts {function} as the last segment.

{
    "production": {
       "events": [{
           "function": "tasks.cleanup",
           "name": "nightly",
           "expression": "cron(0 0   ? *)"
       }]
    }
}

Rule name: my-app-prod-nightly-tasks.cleanup โ€” handler extracts tasks.cleanup.

Total rule name limit: EventBridge rule names are capped at 64 characters. If the combined name exceeds this, Zappa automatically shortens the lambda name prefix using a SHA-1 hash. If the function name portion (or {name}-{function}) exceeds 63 characters, Zappa raises an error.

Undeploy

If you need to remove the API Gateway and Lambda function that you have previously published, you can simply:

$ zappa undeploy production

You will be asked for confirmation before it executes.

If you enabled CloudWatch Logs for your API Gateway service and you don't want to keep those logs, you can specify the --remove-logs argument to purge the logs for your API Gateway and your Lambda function:

$ zappa undeploy production --remove-logs

Package

If you want to build your application package without actually uploading and registering it as a Lambda function, you can use the package command:

$ zappa package production

If you have a zip callback in your callbacks setting, this will also be invoked.

{
    "production": { // The name of your stage
        "callbacks": {
            "zip": "myapp.zipcallback"// After creating the package
        }
    }
}

You can also specify the output filename of the package with -o:

$ zappa package production -o myawesomepackage.zip

How Zappa Makes Packages

Zappa will automatically package your active virtual environment into a package which runs smoothly on AWS Lambda.

During this process, it will replace any local dependencies with AWS Lambda compatible versions. Dependencies are included in this order:

  • Lambda-compatible manylinux wheels from a local cache
  • Lambda-compatible manylinux wheels from PyPI
  • Packages from the active virtual environment
  • Packages from the local project directory
It also skips certain unnecessary files, and ignores any .py files if .pyc files are available.

In addition, Zappa will also automatically set the correct execution permissions, configure package settings, and create a unique, auditable package manifest file.

To further reduce the final package file size, you can:

Template

Similarly to package, if you only want the API Gateway CloudFormation template, use the template command:

$ zappa template production --l your-lambda-arn -r your-role-arn

Note that you must supply your own Lambda ARN and Role ARNs in this case, as they may not have been created for you.

You can get the JSON output directly with --json, and specify the output file with --output.

Status

If you need to see the status of your deployment and event schedules, simply use the status command.

$ zappa status production

Tailing Logs

You can watch the logs of a deployment by calling the tail management command.

$ zappa tail production

By default, this will show all log items. In addition to HTTP and other events, anything printed to stdout or stderr will be shown in the logs.

You can use the argument --http to filter for HTTP requests, which will be in the Apache Common Log Format.

$ zappa tail production --http

Similarly, you can do the inverse and only show non-HTTP events and log messages:

$ zappa tail production --non-http

If you don't like the default log colors, you can turn them off with --no-color.

You can also limit the length of the tail with --since, which accepts a simple duration string:

$ zappa tail production --since 4h # 4 hours $ zappa tail production --since 1m # 1 minute $ zappa tail production --since 1mm # 1 month

You can filter out the contents of the logs with --filter, like so:

$ zappa tail production --http --filter "POST" # Only show POST HTTP requests

Note that this uses the CloudWatch Logs filter syntax.

To tail logs without following (to exit immediately after displaying the end of the requested logs), pass --disable-keep-open:

$ zappa tail production --since 1h --disable-keep-open

Remote Function Invocation

You can execute any function in your application directly at any time by using the invoke command.

For instance, suppose you have a basic application in a file called "myapp.py", and you want to invoke a function in it called "myfunction". Once your application is deployed, you can invoke that function at any time by calling:

$ zappa invoke production myapp.myfunction

Any remote print statements made and the value the function returned will then be printed to your local console.

You can also invoke interpretable Python 3.9/3.10/3.11/3.12/3.13/3.14 strings directly by using --raw, like so:

$ zappa invoke production "print(1 + 2 + 3)" --raw

For instance, it can come in handy if you want to create your first superuser on a RDS database running in a VPC (like Serverless Aurora):

$ zappa invoke staging "from django.contrib.auth import getusermodel; User = getusermodel(); User.objects.create_superuser('username', 'email', 'password')" --raw

If you need to invoke a specific version of your function, you can use the --qualifier option to specify it.

$ zappa invoke production myapp.myfunction --qualifier 123

Function aliases are also supported as qualifiers.

Django Management Commands

As a convenience, Zappa can also invoke remote Django 'manage.py' commands with the manage command. For instance, to perform the basic Django status check:

$ zappa manage production showmigrations admin

Obviously, this only works for Django projects which have their settings properly defined.

For commands which have their own arguments, you can also pass the command in as a string, like so:

$ zappa manage production "shell --version"

As with invoke, a qualifier can be added to specify the version of your function that's used to execute the command. This can be particularly important when running certain commands such as migrate directly after a new deployment:

$ zappa manage production migrate admin --qualifier 123

Commands which require direct user input, such as createsuperuser, should be replaced by commands which use zappa invoke <env> --raw.

For more Django integration, take a look at the zappa-django-utils project.

SSL Certification

Zappa can be deployed to custom domain names and subdomains with custom SSL certificates, Let's Encrypt certificates, and AWS Certificate Manager (ACM) certificates.

Currently, the easiest of these to use are the AWS Certificate Manager certificates, as they are free, self-renewing, and require the least amount of work.

Once configured as described below, all of these methods use the same command:

$ zappa certify

When deploying from a CI/CD system, you can use:

$ zappa certify --yes

to skip the confirmation prompt.

Deploying to a Domain With AWS Certificate Manager

Amazon provides their own free alternative to Let's Encrypt called AWS Certificate Manager (ACM). To use this service with Zappa:

  • Verify your domain in the AWS Certificate Manager console.
  • In the console, select the N. Virginia (us-east-1) region and request a certificate for your domain or subdomain (sub.yourdomain.tld), or request a wildcard domain (*.yourdomain.tld).
  • Copy the entire ARN of that certificate and place it in the Zappa setting certificate_arn.
  • Set your desired domain in the domain setting.
  • Call $ zappa certify to create and associate the API Gateway distribution using that certificate.

Deploying to a Domain With a Let's Encrypt Certificate (DNS Auth)

If you want to use Zappa on a domain with a free Let's Encrypt certificate using automatic Route 53 based DNS Authentication, you can follow this handy guide.

Deploying to a Domain With a Let's Encrypt Certificate (HTTP Auth)

If you want to use Zappa on a domain with a free Let's Encrypt certificate using HTTP Authentication, you can follow this guide.

However, it's now far easier to use Route 53-based DNS authentication, which will allow you to use a Let's Encrypt certificate with a single $ zappa certify command.

Deploying to a Domain With Your Own SSL Certs

  • The first step is to create a custom domain and obtain your SSL cert / key / bundle.
  • Ensure you have set the domain setting within your Zappa settings JSON - this will avoid problems with the Base Path mapping between the Custom Domain and the API invoke URL, which gets the Stage Name appended in the URI
  • Add the paths to your SSL cert / key / bundle to the certificate, certificatekey, and certificatechain settings, respectively, in your Zappa settings JSON
  • Set route53_enabled to false if you plan on using your own DNS provider, and not an AWS Route53 Hosted zone.
  • Deploy or update your app using Zappa
  • Run $ zappa certify to upload your certificates and register the custom domain name with your API gateway.

Executing in Response to AWS Events

Similarly, you can have your functions execute in response to events that happen in the AWS ecosystem, such as S3 uploads, DynamoDB entries, Kinesis streams, SNS messages, and SQS queues.

In your zappasettings.json file, define your event sources and the function you wish to execute. For instance, this will execute yourmodule.processuploadfunction in response to new objects in your my-bucket S3 bucket. Note that processupload_function must accept event and context parameters.

{
    "production": {
       ...
       "events": [{
            "function": "yourmodule.processupload_function",
            "event_source": {
                  "arn":  "arn:aws:s3:::my-bucket",
                  "events": [
                    "s3:ObjectCreated:*" // Supported event types: http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#supported-notification-event-types
                  ],
                  "key_filters": [{ // optional
                    "type": "suffix",
                    "value": "yourfile.json"
                  },
                  {
                    "type": "prefix",
                    "value": "prefix/for/your/object"
                  }]
               }
            }],
       ...
    }
}

And then:

$ zappa schedule production

And now your function will execute every time a new upload appears in your bucket!

To access the key's information in your application context, you'll want processuploadfunction to look something like this:

import boto3
s3_client = boto3.client('s3')

def processuploadfunction(event, context): """ Process a file upload. """

# Get the uploaded file's information bucket = event['Records'][0]['s3']['bucket']['name'] # Will be my-bucket key = event['Records'][0]['s3']['object']['key'] # Will be the file path of whatever file was uploaded.

# Get the bytes from S3 s3client.downloadfile(bucket, key, '/tmp/' + key) # Download this file to writable tmp space. file_bytes = open('/tmp/' + key).read()

Similarly, for a Simple Notification Service event:

"events": [
            {
                "function": "yourmodule.yourfunction",
                "event_source": {
                    "arn":  "arn:aws:sns:::your-event-topic-arn",
                    "events": [
                        "sns:Publish"
                    ]
                }
            }
        ]

Optionally you can add SNS message filters:

"events": [
            {
                "function": "yourmodule.yourfunction",
                "event_source": {
                    "arn":  "arn:aws:sns:::your-event-topic-arn",
                    "filters": {
                        "interests": ["python", "aws", "zappa"],
                        "version": ["1.0"]
                    },
                    ...
                }
            }
        ]

DynamoDB and Kinesis are slightly different as it is not event based but pulling from a stream:

"events": [
           {
               "function": "replication.replicate_records",
               "event_source": {
                    "arn":  "arn:aws:dynamodb:us-east-1:1234554:table/YourTable/stream/2016-05-11T00:00:00.000",
                    "startingposition": "TRIMHORIZON", // Supported values: TRIM_HORIZON, LATEST
                    "batch_size": 50, // Max: 1000
                    "enabled": true // Default is false
               }
           }
       ]

SQS is also pulling messages from a stream. Read the AWS Documentation carefully since Lambda calls the SQS DeleteMessage API on your behalf once your function completes successfully. By default, if your function encounters an error while processing a batch, all messages in that batch become visible in the queue again.

"events": [
           {
               "function": "yourmodule.processmessages",
               "event_source": {
                    "arn":  "arn:aws:sqs:us-east-1:12341234:your-queue-name-arn",
                    "batch_size": 10, // Maximum: 10 for FIFO and 10,000 for Standard. Use 1 to trigger immediate processing
                    "enabled": true // Default is false
               }
           }
       ]

For configuring Lex Bot's intent triggered events:

"bot_events": [
        {
            "function": "lexbot.handlers.book_appointment.handler",
            "event_source": {
                "arn": "arn:aws:lex:us-east-1:01234123123:intent:TestLexEventNames:$LATEST", // optional. In future it will be used to configure the intent
                "intent":"intentName", // name of the bot event configured
                "invocation_source":"DialogCodeHook", // either FulfillmentCodeHook or DialogCodeHook
            }
        }
    ]

Events can also take keyword arguments:

"events": [
            {
                "function": "yourmodule.yourrecurring_function", // The function to execute
                "kwargs": {"key": "val", "key2": "val2"},  // Keyword arguments to pass. These are available in the event
                "expression": "rate(1 minute)" // When to execute it (in cron or rate format)
            }
       ]

To get the keyword arguments you will need to look inside the event dictionary:

def yourrecurringfunction(event, context):
    mykwargs = event.get("kwargs")  # dict of kwargs given in zappasettings file

You can find more example event sources here.

Asynchronous Task Execution

Zappa also now offers the ability to seamlessly execute functions asynchronously in a completely separate AWS Lambda instance!

For example, if you have a Flask API for ordering a pie, you can call your bake function seamlessly in a completely separate Lambda instance by using the zappa.asynchronous.task decorator like so:

from flask import Flask
from zappa.asynchronous import task
app = Flask(name)

@task def make_pie(): """ This takes a long time! """ ingredients = get_ingredients() pie = bake(ingredients) deliver(pie)

@app.route('/api/order/pie') def order_pie(): """ This returns immediately! """ make_pie() return "Your pie is being made!"

And that's it! Your API response will return immediately, while the make_pie function executes in a completely different Lambda instance.

When calls to @task decorated functions or the zappa.asynchronous.run command occur outside of Lambda, such as your local dev environment, the functions will execute immediately and locally. The zappa asynchronous functionality only works when in the Lambda environment or when specifying Remote Invocations.

Catching Exceptions

Putting a try..except block on an asynchronous task like this:

@task
def make_pie():
    try:
        ingredients = get_ingredients()
        pie = bake(ingredients)
        deliver(pie)
    except Fault as error:
        """send an email"""
    ...
    return Response('Web services down', status=503)

will cause an email to be sent twice for the same error. See asynchronous retries at AWS. To work around this side-effect, and have the fault handler execute only once, change the return value to:

@task
def make_pie():
    try:
        """code block"""
    except Fault as error:
        """send an email"""
    ...
    return {} #or return True

Task Sources

By default, this feature uses direct AWS Lambda invocation. You can instead use AWS Simple Notification Service as the task event source by using the task_sns decorator, like so:

from zappa.asynchronous import task_sns
@task_sns

Using SNS also requires setting the following settings in your zappa_settings:

{
  "dev": {
    ..
      "async_source": "sns", // Source of async tasks. Defaults to "lambda"
      "async_resources": true, // Create the SNS topic to use. Defaults to true.
    ..
    }
}

This will automatically create and subscribe to the SNS topic the code will use when you call the zappa schedule command.

Using SNS will also return a message ID in case you need to track your invocations.

Direct Invocation

You can also use this functionality without a decorator by passing your function to zappa.asynchronous.run, like so:

from zappa.asynchronous import run

run(your_function, args, kwargs) # Using Lambda run(your_function, args, kwargs, service='sns') # Using SNS

Remote Invocations

By default, Zappa will use lambda's current function name and current AWS region. If you wish to invoke a lambda with a different function name/region or invoke your lambda from outside of lambda, you must specify the remoteawslambdafunctionname and remoteawsregion arguments so that the application knows which function and region to use. For example, if some part of our pizza making application had to live on an EC2 instance, but we wished to call the make_pie() function on its own Lambda instance, we would do it as follows:

@task(remoteawslambdafuncti, remoteaws_region='us-east-1')
def make_pie():
   """ This takes a long time! """
   ingredients = get_ingredients()
   pie = bake(ingredients)
   deliver(pie)

If those task() parameters were not used, then EC2 would execute the function locally. These same remoteawslambdafunctionname and remoteawsregion arguments can be used on the zappa.asynchronous.run() function as well.

Restrictions

The following restrictions to this feature apply:

  • Functions must have a clean import path -- i.e. no closures, lambdas, or methods.
  • args and kwargs must be JSON-serializable.
  • The JSON-serialized arguments must be within the size limits for Lambda (256K) or SNS (256K) events.
All of this code is still backwards-compatible with non-Lambda environments - it simply executes in a blocking fashion and returns the result.

Running Tasks in a VPC

If you're running Zappa in a Virtual Private Cloud (VPC), you'll need to configure your subnets to allow your lambda to communicate with services inside your VPC as well as the public Internet. A minimal setup requires two subnets.

In subnet-a:

  • Create a NAT
  • Create an Internet gateway
  • In the route table, create a route pointing the Internet gateway to 0.0.0.0/0.
In subnet-b:
  • Place your lambda function
  • In the route table, create a route pointing the NAT that belongs to subnet-a to 0.0.0.0/0.
You can place your lambda in multiple subnets that are configured the same way as subnet-b for high availability.

Some helpful resources are this tutorial, this other tutorial and this AWS doc page.

Responses

It is possible to capture the responses of Asynchronous tasks.

Zappa uses DynamoDB as the backend for these.

To capture responses, you must configure a asyncresponsetable in zappasettings. This is the DynamoDB table name. Then, when decorating with @task, pass captureresponse=True.

Async responses are assigned a response_id. This is returned as a property of the LambdaAsyncResponse (or SnsAsyncResponse) object that is returned by the @task decorator.

Example:

from zappa.asynchronous import task, getasyncresponse
from flask import Flask, abort, url_for, redirect, request, jsonify
from time import sleep

app = Flask(name)

@app.route('/payload') def payload(): delay = request.args.get('delay', 60) x = longrunner(delay) return redirect(urlfor('response', responseid=x.response_id))

@app.route('/async-response/<response_id>') def response(response_id): response = getasyncresponse(response_id) if response is None: abort(404)

if response['status'] == 'complete': return jsonify(response['response'])

sleep(5)

return "Not yet ready. Redirecting.", 302, { 'Content-Type': 'text/plain; charset=utf-8', 'Location': urlfor('response', responseid=response_id, backoff=5), 'X-redirect-reason': "Not yet ready.", }

@task(capture_response=True) def longrunner(delay): sleep(float(delay)) return {'MESSAGE': "It took {} seconds to generate this.".format(delay)}

Advanced Settings

There are other settings that you can define in your local settings to change Zappa's behavior. Use these at your own risk!

``javascript { "dev": { "additionaltextmimetypes": [], // allows you to provide additional mimetypes to be handled as text when binary_support is true. "albenabled": false, // enable provisioning of application load balancing resources. If set to true, you must fill out the albvpc_config option as well. "albvpcconfig": { "CertificateArn": "youracmcertificate_arn", // ACM certificate ARN for ALB "SubnetIds": [], // list of subnets for ALB "SecurityGroupIds": [] // list of security groups for ALB }, "apikeyrequired": false, // enable securing API Gateway endpoints with x-api-key header (default False) "apikey": "yourapikeyid", // optional, use an existing API key. The option "apikeyrequired" must be true to apply "app_type": "asgi", // optional, set to "asgi" to run an ASGI app (FastAPI, Starlette, Quart). When omitted, Zappa auto-detects async callables or defaults to WSGI. "apigateway_enabled": true, // Set to false if you don't want to create an API Gateway resource. Default true. "apigateway_description": "My funky application!", // Define a custom description for the API Gateway console. Default None. "assumepolicy": "myassume_policy.json", // optional, IAM assume policy JSON file "attachpolicy": "myattach_policy.json", // optional, IAM attach policy JSON file "apigatewaypolicy": "myapigateway_policy.json", // optional, API Gateway resource policy JSON file "functionurlenabled": false, // optional, set to true if you want to enable function URL. Default false. "functionurlconfig": { "authorizer": "NONE", // required if function url is enabled. default None. https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html "cors": { // set to false if disable cors. "allowedOrigins": [], // The origins that can access your function URL. default [*] "allowedHeaders": [], // The HTTP headers that origins can include in requests to your function URL. "allowedMethods": [], // The HTTP methods that are allowed when calling your function URL. For example: GET , POST , DELETE , or the wildcard character ( ). default [] "allowCredentials": false, //required, Whether to allow cookies or other credentials in requests to your function URL. default false. "exposedResponseHeaders": [], The HTTP headers in your function response that you want to expose to origins that call your function URL. "maxAge": 0 // The maximum amount of time, in seconds, that web browsers can cache results of a preflight request. default 0. } }, // NOTE: Function URLs do NOT include stage names in their paths. Unlike API Gateway v1/v2 which include // the stage name in the URL (e.g., /dev/mypath), Function URLs route directly to your app (e.g., /mypath). // This means SCRIPTNAME will be empty for Function URL requests, and PATHINFO will contain the full path. // // NOTE: When functionurlenabled is true with authorizer: "NONE", Zappa attaches TWO // resource-policy statements with Principal: "*": FunctionURLAllowPublicAccess for // lambda:InvokeFunctionUrl and FunctionURLAllowPublicAccessInvoke for lambda:InvokeFunction. // Both are required for unsigned calls to succeed; the AWS docs example at // https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html only shows the first statement, // but in practice the URL returns 403 AccessDeniedException without the second (see #1393). // If you are adding a Function URL manually (e.g. outside Zappa) and seeing 403s with NONE // auth, this two-statement shape is the missing piece. "apigateway_version": "v1", // optional, API Gateway version to use. Can be "v1" or "v2". Default "v1". "architecture": "x8664", // optional, Set Lambda Architecture, defaults to x8664. For Graviton 2 use: arm64 "async_source": "sns", // Source of async tasks. Defaults to "lambda" "async_resources": true, // Create the SNS topic and DynamoDB table to use. Defaults to true. "asyncresponsetable": "yourdynamodbtable_name", // the DynamoDB table name to use for captured async responses; defaults to None (can't capture) "asyncresponsetablereadcapacity": 1, // DynamoDB table read capacity; defaults to 1 "asyncresponsetablewritecapacity": 1, // DynamoDB table write capacity; defaults to 1 "awsendpointurls": { "awsservicename": "endpointurl" }, // a dictionary of endpointurls that emulate the appropriate service. Usually used for testing, for instance with localstack. "awsenvironmentvariables" : {"yourkey": "yourvalue"}, // A dictionary of environment variables that will be available to your deployed app via AWS Lambdas native environment variables. See also "environmentvariables" and "remoteenv" . Default {}. "awskmskeyarn": "yourawskmskey_arn", // Your AWS KMS Key ARN "aws_region": "aws-region-name", // optional, uses region set in profile or environment variables if not set here, "binary_support": true, // Enable automatic MIME-type based response encoding through API Gateway. Default true. "callbacks": { // Call custom functions during the local Zappa deployment/update process "settings": "myapp.settingscallback", // After loading the settings "zip": "myapp.zipcallback", // After creating the package "post": "myapp.postcallback", // After command has executed }, "cacheclusterenabled": false, // Use APIGW cache cluster (default False) "cacheclustersize": 0.5, // APIGW Cache Cluster size (default 0.5) "cacheclusterttl": 300, // APIGW Cache Cluster time-to-live (default 300) "cacheclusterencrypted": false, // Whether or not APIGW Cache Cluster encrypts data (default False) "certificate": "my_cert.crt", // SSL certificate file location. Used to manually certify a custom domain "certificatekey": "mykey.key", // SSL key file location. Used to manually certify a custom domain "certificatechain": "mycert_chain.pem", // SSL certificate chain file location. Used to manually certify a custom domain "certificate_arn": "arn:aws:acm:us-east-1:1234512345:certificate/aaaa-bbb-cccc-dddd", // ACM certificate ARN (needs to be in us-east-1 region). "cloudwatchloglevel": "OFF", // Enables/configures a level of logging for the given staging. Available options: "OFF", "INFO", "ERROR", default "OFF". "cloudwatchdatatrace": false, // Logs all data about received events. Default false. "cloudwatchmetricsenabled": false, // Additional metrics for the API Gateway. Default false. "cognito": { // for Cognito event triggers "user_pool": "user-pool-id", // User pool ID from AWS Cognito "triggers": [{ "source": "PreSignUp_SignUp", // triggerSource from http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-pre-signup "function": "myapp.presignup_function" }] }, "contextheadermappings": { "HTTPheadername": "APIGatewaycontext_variable" }, // A dictionary mapping HTTP header names to API Gateway context variables "cors": false, // Enable Cross-Origin Resource Sharing. Default false. If true, simulates the "Enable CORS" button on the API Gateway console. Can also be a dictionary specifying lists of "allowedheaders", "allowedmethods", and string of "allowed_origin" "deadletterarn": "arn:aws:<sns/sqs>:::my-topic/queue", // Optional Dead Letter configuration for when Lambda async invoke fails thrice "debug": true, // Print Zappa configuration errors tracebacks in the 500. Default true. "deletelocalzip": true, // Delete the local zip archive after code updates. Default true. "deletes3zip": true, // Delete the s3 zip archive. Default true. "djangosettings": "yourproject.production_settings", // The modular path to your Django project's settings. For Django projects only. "domain": "yourapp.yourdomain.com", // Required if you're using a domain "base_path": "your-base-path", // Optional base path for API gateway custom domain base path mapping. Default None. Not supported for use with Application Load Balancer event sources. "environmentvariables": {"yourkey": "yourvalue"}, // A dictionary of environment variables that will be available to your deployed app. See also "remoteenv" and "awsenvironmentvariables". Default {}. "events": [ { // Recurring events "function": "yourmodule.yourrecurringfunction", // The function to execute (Pattern: [.A-Za-z0-9]+). "expression": "rate(1 minute)" // When to execute it (in cron or rate format) }, { // AWS Reactive events "function": "yourmodule.yourreactivefunction", // The function to execute (Pattern: [.A-Za-z0-9]+). "event_source": { "arn": "arn:aws:s3:::my-bucket", // The ARN of this event source "events": [ "s3:ObjectCreated:*" // The specific event to execute in response to. ] } } ], "endpoint_configuration": ["EDGE", "REGIONAL", "PRIVATE"], // Specify APIGateway endpoint None (default) or list ED


README truncated. View on GitHub

ยฉ 2026 GitRepoTrend ยท zappa/Zappa ยท Updated daily from GitHub