Skip to content

Serverless Deploy — Deployment Strategies and CI/CD

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Serverless Deploy. We cover key concepts, practical examples, and best practices to help you master this topic.

Serverless deployment involves packaging function code, uploading to AWS, updating function configuration, and promoting changes through environments using CI/CD pipelines and deployment strategies.

What You'll Learn

By the end of this lesson you will understand serverless deployment workflows, canary deployments with Lambda aliases, CI/CD pipeline setup, rollback strategies, and environment promotion.

Why It Matters

Serverless deployments are simple in theory but complex in practice. A bad deployment can cause downtime, data loss, or security breaches. Understanding deployment strategies ensures safe, repeatable, and auditable releases.

Real-World Use

DodaBrowser's serverless backend uses a CI/CD pipeline with GitHub Actions. Merging to main triggers a staging deployment, automated tests run against the staging API, and a manual approval gate promotes to production with canary traffic shifting.

flowchart LR
    G[Git Push] --> CI[CI Pipeline]
    CI --> B[Build Package]
    B --> D[Deploy to Dev]
    D --> T[Automated Tests]
    T -->|Pass| S[Deploy to Staging]
    S --> A[Manual Approval]
    A --> C[Canary Deploy to Prod]
    C --> R[Rollback if Errors]
    style D fill:#f90,color:#fff

Deployment with Serverless Framework

The Serverless Framework packages your code, creates a CloudFormation stack, and deploys all resources.

# Deploy all functions and resources
sls deploy --stage production

# Deploy a single function (faster)
sls deploy function -f createUser

# Deploy only the function code without infrastructure changes
sls deploy function -f createUser --update-config

# Package without deploying
sls package --stage production
# deploy_process.py
# Understanding the deployment process

def simulate_deploy(stage="dev"):
    steps = [
        "1. Validate serverless.yml syntax",
        "2. Package function code and dependencies",
        "3. Upload to S3 deployment bucket",
        "4. Generate CloudFormation template",
        "5. Execute CloudFormation stack change set",
        "6. Update Lambda function code",
        "7. Update Lambda function configuration",
        "8. Deploy API Gateway stage",
    ]
    
    print(f"Deploying to {stage}...\n")
    for step in steps:
        print(f"  {step}")
    print(f"\n  Stack: my-service-{stage}")
    print(f"  API URL: https://abc123.execute-api.us-east-1.amazonaws.com/{stage}/")

simulate_deploy("production")

Expected output:

Deploying to production...

  1. Validate serverless.yml syntax
  2. Package function code and dependencies
  3. Upload to S3 deployment bucket
  ...
  API URL: https://abc123.execute-api.us-east-1.amazonaws.com/production/

Canary Deployments

Lambda aliases support canary traffic shifting where a percentage of traffic goes to a new version.

# canary_deploy.py
# Canary deployment simulation

class CanaryDeployment:
    def __init__(self, function_name):
        self.function = function_name
        self.current_version = 1
        self.new_version = None
    
    def deploy_canary(self, traffic_percent=5):
        self.new_version = self.current_version + 1
        print(f"Deploying v{self.new_version} to {self.function}")
        print(f"  Routing {traffic_percent}% of traffic to new version")
        print("  Monitoring errors and latency...")
        
        if traffic_percent <= 10:
            print("  -> Canary: No errors detected")
            self.promote()
        else:
            print("  -> Canary: Error rate exceeded threshold")
            self.rollback()
    
    def promote(self):
        print(f"  Promoting v{self.new_version} to 100% traffic")
        self.current_version = self.new_version
    
    def rollback(self):
        print(f"  Rolling back to v{self.current_version}")

deploy = CanaryDeployment("order-api")
deploy.deploy_canary(traffic_percent=5)

Expected output:

Deploying v2 to order-api
  Routing 5% of traffic to new version
  Monitoring errors and latency...
  -> Canary: No errors detected
  Promoting v2 to 100% traffic

Rollback Strategies

If a deployment causes issues, rollback to a previous version quickly.

# rollback.py
# Rollback strategies

def simulate_rollback(function_name, deploy_id, reason):
    print(f"Rolling back {function_name}")
    print(f"  Failed deployment: {deploy_id}")
    print(f"  Reason: {reason}")
    print(f"  Reverting to previous version...")
    
    steps = [
        "Update alias to point to previous version",
        "Redeploy previous CloudFormation stack",
        "Restore API Gateway stage",
        "Clear any warmed execution environments",
    ]
    
    for s in steps:
        print(f"  -> {s}")
    
    print(f"  Rollback complete. Function restored to previous state.")

simulate_rollback("create-user", "deploy-42", "Error rate exceeded 5% threshold")

CI/CD Pipeline

Set up automated deployment with GitHub Actions, GitLab CI, or AWS CodePipeline.

# .github/workflows/deploy.yml
name: Deploy Serverless
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npm test
      - name: Deploy to staging
        run: npx sls deploy --stage staging
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Common Mistakes

  1. Deploying directly to production without staging: Always deploy to staging first, run tests, then promote to production.

  2. Not using function-level deployment: sls deploy deploys everything. Use sls deploy function -f name for faster iterations.

  3. Forgetting to bundle dependencies: Functions fail at runtime with import errors if dependencies are not included in the deployment package.

  4. Not setting up rollback automation: Manual rollbacks take too long during incidents. Automate rollback on error threshold breach.

  5. Ignoring IAM permission drift: When resources are updated outside the Framework, deployments may fail. Use drift detection.

Practice Questions

  1. What is the difference between sls deploy and sls deploy function? sls deploy deploys the entire stack. sls deploy function updates only a single function's code.

  2. How do canary deployments work with Lambda? Lambda aliases support routing a percentage of traffic to a new version while monitoring for errors.

  3. What should you do if a deployment causes errors? Rollback to the previous version using the alias or redeploy the previous CloudFormation stack.

  4. How do you set up a CI/CD pipeline for serverless? Use GitHub Actions or AWS CodePipeline to run tests on every push and deploy to staging automatically.

  5. Challenge: Create a deployment pipeline that deploys to dev on every PR, staging on merge to main, and production with manual approval and canary traffic shifting.

FAQ

How long does a Serverless Framework deployment take?

Typically 30-60 seconds for function-only updates, 2-5 minutes for full stack deployments.

Can I rollback a Serverless Framework deployment?

Yes, use sls rollback to revert to a previous deployment timestamp.

How does the Framework handle environment variables?

Variables are stored in the CloudFormation template or AWS SSM, not hardcoded in the YAML.

Can I deploy only infrastructure changes?

Yes, sls deploy updates both code and infrastructure. Use sls deploy function for code-only updates.

What happens if a deployment fails mid-way?

CloudFormation handles rollback automatically for infrastructure failures. Code updates may leave inconsistencies.

Mini Project

Create a deployment script that packages a serverless function, deploys to staging, runs health check tests, promotes to production with a canary, and rolls back on failure.

import random

def deploy_pipeline():
    stages = {
        "package": {"status": "pending"},
        "deploy-staging": {"status": "pending"},
        "tests": {"status": "pending"},
        "approve": {"status": "pending"},
        "canary-prod": {"status": "pending"},
        "promote": {"status": "pending"},
    }
    
    for stage in stages:
        print(f"[{stage}] Running...")
        stages[stage]["status"] = "passed" if random.random() > 0.1 else "failed"
        
        if stages[stage]["status"] == "failed":
            print(f"[{stage}] FAILED - Initiating rollback")
            for prev in reversed(list(stages.keys())):
                if stages[prev]["status"] == "passed":
                    print(f"  Rolling back: {prev}")
                    stages[prev]["status"] = "rolled-back"
            return False
        
        print(f"[{stage}] OK")
    
    print("Deployment complete!")
    return True

deploy_pipeline()

What's Next

Next: Serverless Security (IAM) for access control.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro