# Serverless vs. Container-Based Compute

> Developer simplicity and auto-scaling vs. control and performance. Cold starts, execution limits, GPU support, cost model, and operational overhead trade-offs.

- **Category**: Trade-offs
- **Subcategory**: Cloud Infrastructure
- **Canonical URL**: https://designpattern.fyi/trade_offs/serverless-vs-containers/

---

## Description
**Intent**: Choose between serverless computing (Lambda, Cloud Run) for simplicity and auto-scaling versus container-based compute (EKS, GKE, ECS) for control and performance.

**Context**: Serverless offers zero infrastructure management, automatic scaling to zero, and pay-per-millisecond pricing — but has cold starts (100ms-3s), execution limits (15 min for Lambda), limited GPU support, and vendor lock-in. Containers provide full control, no cold starts when pre-warmed, unlimited execution time, full GPU support, but require operational overhead and per-hour pricing.

**Solution**: Use serverless for API endpoints with spiky traffic, lightweight preprocessing, event-driven triggers, and sub-15-minute inference with small models. Use containers for GPU workloads, stateful applications, long-running jobs, and fine-grained resource control. Eliminate cold starts with warm instances, provisioned concurrency, or min-instances > 0.



## Use Cases
API gateway with spiky traffic using serverless for auto-scaling. ML inference serving using containers for GPU access and consistent performance. Data processing pipeline using serverless for event-driven execution.



## Implementation Example

```javascript
// Serverless vs. Container-Based Compute

// Serverless (AWS Lambda) - Auto-scaling, pay-per-use
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();

// Serverless function for lightweight processing
async function processEvent(event) {
  const response = await lambda.invoke({
    FunctionName: 'event-processor',
    Payload: JSON.stringify(event),
    InvocationType: 'RequestResponse' // Synchronous
  }).promise();

  return JSON.parse(response.Payload);
}

// Container (ECS/Kubernetes) - Consistent performance, GPU support
const ecs = new AWS.ECS();

async function runMLInferenceTask(imageData) {
  const response = await ecs.runTask({
    cluster: 'ml-inference-cluster',
    taskDefinition: 'ml-inference-task',
    launchType: 'FARGATE',
    networkConfiguration: {
      awsvpcConfiguration: {
        subnets: ['subnet-123'],
        assignPublicIp: 'ENABLED'
      }
    },
    overrides: {
      containerOverrides: [{
        name: 'ml-inference',
        environment: [{ name: 'IMAGE_DATA', value: imageData }]
      }]
    }
  }).promise();

  return response.tasks[0].taskArn;
}

// Hybrid: Serverless for orchestration, containers for heavy lifting
async function hybridPipeline(data) {
  // Step 1: Lightweight preprocessing (serverless)
  const preprocessed = await processEvent({ type: 'preprocess', data });

  // Step 2: Heavy computation (containers)
  const taskArn = await runMLInferenceTask(preprocessed);

  // Step 3: Lightweight postprocessing (serverless)
  const result = await processEvent({ type: 'postprocess', taskArn });
  return result;
}

// Cold start mitigation: Provisioned concurrency
async function provisionLambdaConcurrency() {
  await lambda.putProvisionedConcurrencyConfig({
    FunctionName: 'api-handler',
    ProvisionedConcurrentExecutions: 5, // Keep 5 warm instances
    Qualifier: 'production'
  }).promise();
}

```



## Trade-offs


### Advantages

- map[Serverless:zero infrastructure management, automatic scaling]

- map[Serverless:cost-effective for low-traffic workloads]

- map[Containers:full control over environment and dependencies]

- map[Containers:consistent performance, no cold starts when pre-warmed]




### Considerations & Drawbacks

- map[Serverless:cold starts, execution time limits, limited GPU]

- map[Serverless:vendor lock-in, debugging complexity]

- map[Containers:operational overhead, per-hour pricing waste]

- map[Containers:require scaling management and monitoring]







