Scaling Serverless Without Slowing Down Our Development Velocity

Scaling Serverless Without Slowing Down Our Development Velocity

At Hoomanely, we're building a preventive pet healthcare platform for pet parents that has tools and features ranging from pet-parents community to a AI powered pet care chat assistant. Our mission demands rapid iteration—we need to test hypotheses quickly, deploy features fast, and scale efficiently without the overhead of managing infrastructure.

During our rapid prototyping phase, we faced a critical challenge: how do we deploy Python applications to AWS Lambda quickly and reliably while maintaining the agility needed for fast experimentation? What started as an exciting serverless journey quickly turned into a deployment nightmare that threatened to slow down our entire development cycle.


The Problem: Deployment Friction at Every Turn

Our initial approach seemed straightforward—manually package our Flask application, upload it to AWS Lambda, configure API Gateway, set up environment variables, and deploy. Simple, right? Not quite.

What We Actually Encountered

Packaging Hell: Every deployment meant creating a deployment package with all dependencies, zipping it up, and uploading to S3. For a typical Flask app with libraries like pandas, numpy, and our ML dependencies, packages easily exceeded 50MB. Lambda's direct upload limit is 50MB, forcing us to use S3 for every single deployment.

Configuration Sprawl: Each Lambda function needed manual configuration in the AWS Console—memory settings, timeout values, environment variables, IAM roles, VPC settings. Multiply this by multiple environments (dev, staging, production) and multiple functions, and you have a maintenance nightmare.

API Gateway Complexity: Wiring up API Gateway to Lambda functions manually is tedious. Every endpoint requires careful configuration of integration requests, responses, CORS settings, and authorisation. One misconfiguration and your API returns cryptic errors.

Rollback Anxiety: When something broke in production (and it did), rolling back meant remembering which version worked, finding that deployment package, and repeating the entire upload process. No simple "undo" button.

Development vs. Production Gap: Code that worked perfectly on our local machines would mysteriously fail on Lambda. Debugging meant adding print statements, repackaging, uploading, and checking CloudWatch logs—a cycle that could take 5-10 minutes per iteration.

The most frustrating part? Each deployment cycle took 15-20 minutes of manual work. For a team iterating multiple times daily, this was unacceptable.


Exploring the Solution Space

We knew we weren't the first team to face this problem. We evaluated several approaches:

Option 1: AWS SAM (Serverless Application Model)

SAM promised infrastructure-as-code for serverless applications with a cleaner deployment process.

Pros:

  • Official AWS tool with good documentation
  • YAML-based configuration for reproducible deployments
  • Built-in support for local testing

Cons:

  • Still required understanding CloudFormation
  • Configuration files quickly became verbose
  • Limited support for Flask/Django-specific patterns
  • Deployment times remained slow for Python applications with large dependencies

Option 2: Serverless Framework

The Serverless Framework offered a provider-agnostic approach with a large community.

Pros:

  • Works across AWS, Azure, and GCP
  • Plugin ecosystem for extended functionality
  • Good documentation and community support

Cons:

  • JavaScript/Node.js-centric with Python as a secondary concern
  • Required additional plugins for Python packaging
  • Configuration still felt heavy for simple Flask apps
  • Dependency management wasn't optimised for Python's ecosystem

Option 3: Custom CI/CD Scripts

We considered building our own deployment automation using GitHub Actions or GitLab CI.

Pros:

  • Complete control over the deployment process
  • Customisable to our exact needs

Cons:

  • Significant upfront investment in building and maintaining scripts
  • Would need to solve packaging, dependency management, and AWS integration ourselves
  • Team would need to become experts in deployment tooling instead of focusing on product

None of these felt like the right fit. We needed something Python-first, dead simple, and fast.


Zappa: The Python-First Solution

Zappa caught our attention with a simple promise: deploy Python WSGI applications to AWS Lambda with a single command. No complicated configuration, no infrastructure knowledge required, just zappa deploy.

What Makes Zappa Different

Zappa is purpose-built for Python web frameworks. It understands Flask, Django, Pyramid, and Bottle out of the box. More importantly, it treats Lambda and API Gateway as implementation details, not configuration surfaces you need to master.

The Setup: Installing Zappa took one command: pip install zappa. Initialising it for our project took another: zappa init. Zappa asked a few questions (Which AWS profile? Which environment name? Which Python version?) and generated a minimal zappa_settings.json:

{
    "dev": {
        "app_function": "app.app",
        "aws_region": "ap-south-1",
        "project_name": "hoomanely-api",
        "runtime": "python3.9",
        "s3_bucket": "hoomanely-zappa-deploys"
    }
}

That's it. Fifty lines of configuration replaced with eight.

The First Deploy: Running zappa deploy dev triggered magic. Zappa:

  • Packaged our application and dependencies intelligently
  • Created an optimised deployment package using slim, pre-compiled wheels
  • Set up Lambda functions with sensible defaults
  • Configured API Gateway with all routes automatically
  • Generated a working API endpoint

Total time: 2 minutes. We went from no infrastructure to a working API in 120 seconds.

The Benefits We Actually Got

Instant Iteration: Subsequent deployments use zappa update dev, which is even faster—typically 30-45 seconds. The same deployment that took 15-20 minutes manually now happens while we grab coffee.

Intelligent Dependency Management: Zappa automatically detects which packages need special handling. Libraries like numpy and pandas get replaced with Lambda-optimised versions. Large dependencies are pulled from Lambda Layers. We stopped worrying about package size.

Zero-Downtime Deploys: Zappa handles deployment atomically. It uploads the new version, switches traffic, then cleans up. If something fails, the old version keeps running.

Effortless Rollback: zappa rollback dev instantly reverts to the previous deployment. We've used this in production twice, each time breathing a sigh of relief that it took 10 seconds instead of 10 minutes.

Environment Parity: The same Flask app that runs on our laptops runs on Lambda without modification. Zappa handles the WSGI-to-Lambda translation transparently. Debugging became straightforward again.

CloudWatch Integration: zappa tail dev streams logs in real-time to our terminal. No more switching to the AWS Console and hunting through CloudWatch.

Real-World Impact

Here's what changed for our team:

  • Deploy frequency: From 2-3 times per week to 2-3 times per day
  • Deployment time: From 15-20 minutes to under 1 minute
  • Failed deployments: From ~20% (manual errors) to around 0%
  • Time to rollback: From 10+ minutes to 10 seconds

Key Takeaways

Choose tools designed for your stack: Python-first tools understand Python problems. Zappa's deep integration with WSGI frameworks eliminated entire categories of issues we faced with generic serverless tools.

Deployment friction kills velocity: Every minute spent on deployment is a minute not spent building features. Reducing deployment time from 15 minutes to 1 minute gave us back hours every week.

Simplicity scales better than complexity: Zappa's minimal configuration isn't a limitation—it's a feature. Less configuration means less to break, less to document, and less to maintain.

The best infrastructure is invisible: Zappa abstracted away Lambda and API Gateway complexity without sacrificing power. We gained simplicity without losing flexibility.

If you're building Python web applications and considering serverless, learn from our journey. Don't manually wrestle with Lambda packaging and API Gateway configuration. Don't prematurely optimise with complex frameworks. Start with Zappa, deploy in minutes, and iterate fast.

Read more