Lambda Proxy Integration vs. Standard Integration in API Gateway: A Deep Dive

When connecting AWS API Gateway to a Lambda function, the integration type you choose fundamentally changes what your Lambda receives, what it must return, and how much control API Gateway retains over the request/response lifecycle. Choosing the wrong type silently breaks your API or forces unnecessary boilerplate — understanding the difference is non-negotiable for production-grade serverless APIs.

TL;DR

Dimension Lambda Proxy Integration Standard (Custom) Integration
Event format Fixed, structured JSON envelope (headers, path, query, body, context) Fully customizable via Velocity (VTL) mapping templates
Response format Lambda MUST return a specific JSON structure API Gateway transforms Lambda output via VTL before sending to client
Setup complexity Low — zero mapping templates required High — requires VTL templates for request and response
HTTP control Lambda owns status code, headers, body API Gateway owns status code mapping and header injection
Best for REST APIs, microservices, rapid development Legacy integrations, strict contract enforcement, payload transformation

Architecture: How Each Integration Routes a Request

graph LR Client(["Client"]) subgraph ProxyPath ["Lambda Proxy Integration"] direction LR PGW["API Gateway (No Transformation)"] PLambda["Lambda Function (Receives full event)"] PGW -- "Raw structured JSON event" --> PLambda PLambda -- "statusCode + headers + body (string)" --> PGW end subgraph StandardPath ["Standard Integration"] direction LR SGW["API Gateway + VTL Request Template"] SLambda["Lambda Function (Receives shaped payload)"] SGWR["API Gateway + VTL Response Template"] SGW -- "Custom-shaped JSON event" --> SLambda SLambda -- "Any shape" --> SGWR end Client --> PGW PGW --> Client Client --> SGW SGWR --> Client
  1. Client Request: An HTTP request hits the API Gateway endpoint.
  2. Proxy path (top): API Gateway packages the entire request — method, headers, path parameters, query strings, body, and request context — into a single structured JSON event and forwards it verbatim to Lambda. No transformation occurs at the gateway layer.
  3. Standard path (bottom): API Gateway applies a VTL mapping template to reshape the incoming request before invoking Lambda. The Lambda receives only what the template explicitly extracts.
  4. Response path (Proxy): Lambda returns a structured JSON object; API Gateway passes it directly to the client with no modification.
  5. Response path (Standard): Lambda returns any shape; API Gateway applies a response mapping template and status code mapping before sending to the client.

Lambda Proxy Integration: The Event Object Anatomy

With proxy integration enabled, API Gateway constructs a deterministic event object. Every field is documented and predictable. Below is the canonical structure for a REST API (API Gateway v1):

🔽 [Click to expand] Full Proxy Integration Event Object (REST API / v1)
{
  "resource": "/users/{userId}",
  "path": "/users/42",
  "httpMethod": "GET",
  "headers": {
    "Accept": "application/json",
    "Authorization": "Bearer eyJ...",
    "Host": "abc123.execute-api.us-east-1.amazonaws.com",
    "X-Forwarded-For": "203.0.113.5"
  },
  "multiValueHeaders": {
    "Accept": ["application/json"]
  },
  "queryStringParameters": {
    "include": "profile"
  },
  "multiValueQueryStringParameters": {
    "include": ["profile"]
  },
  "pathParameters": {
    "userId": "42"
  },
  "stageVariables": {
    "env": "prod"
  },
  "requestContext": {
    "accountId": "123456789012",
    "resourceId": "abc123",
    "stage": "prod",
    "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "identity": {
      "sourceIp": "203.0.113.5",
      "userAgent": "Mozilla/5.0"
    },
    "resourcePath": "/users/{userId}",
    "httpMethod": "GET",
    "apiId": "abc123"
  },
  "body": null,
  "isBase64Encoded": false
}

Key Fields Explained

FieldTypePurpose
httpMethodStringHTTP verb (GET, POST, etc.)
pathParametersMap / nullExtracted path template variables
queryStringParametersMap / nullSingle-value query params (last value wins for duplicates)
multiValueQueryStringParametersMap of lists / nullAll values for duplicate query params
headersMap / nullSingle-value HTTP headers
bodyString / nullRaw request body as a string (JSON must be parsed manually)
isBase64EncodedBooleanTrue when binary payload is base64-encoded
requestContextObjectAPI Gateway metadata: stage, caller identity, request ID

Required Lambda Response Format (Proxy Integration)

With proxy integration, Lambda must return this exact structure. Any deviation causes API Gateway to return a 502 Bad Gateway:

{
  "statusCode": 200,
  "headers": {
    "Content-Type": "application/json",
    "X-Custom-Header": "value"
  },
  "multiValueHeaders": {},
  "body": "{\"userId\": 42, \"name\": \"Alice\"}",
  "isBase64Encoded": false
}

Critical: body must be a string, not a JSON object. Serialize it with JSON.stringify() or equivalent before returning.

Standard (Custom) Integration: VTL-Driven Transformation

In standard integration, you author Velocity Template Language (VTL) mapping templates that define exactly what Lambda receives. This gives API Gateway full control over the contract.

🔽 [Click to expand] Example VTL Request Mapping Template
## Request mapping template (application/json)
{
  "userId": "$input.params('userId')",
  "queryParam": "$input.params('include')",
  "authHeader": "$input.params('Authorization')",
  "payload": $input.json('$')
}

Lambda receives only the fields the template extracts — nothing more. The event object shape is entirely under your control, which is powerful but requires discipline to maintain.

Standard Integration Response Flow

API Gateway maps Lambda's output back to HTTP using:

  • Integration Response: Regex-matched on Lambda's error message to select a status code (e.g., .*Not Found.* → 404).
  • Method Response: Defines the HTTP status codes the API officially exposes.
  • Response Mapping Template: VTL that reshapes Lambda's return value into the final HTTP body.

HTTP API (v2) Proxy Integration: The Simplified Event Format

AWS API Gateway HTTP APIs (v2) use a different, leaner event format called payload format version 2.0. This is distinct from the REST API (v1) proxy event above.

🔽 [Click to expand] HTTP API v2 Payload Format 2.0 Event
{
  "version": "2.0",
  "routeKey": "GET /users/{userId}",
  "rawPath": "/users/42",
  "rawQueryString": "include=profile",
  "headers": {
    "accept": "application/json",
    "authorization": "Bearer eyJ..."
  },
  "queryStringParameters": {
    "include": "profile"
  },
  "pathParameters": {
    "userId": "42"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "abc123",
    "http": {
      "method": "GET",
      "path": "/users/42",
      "protocol": "HTTP/1.1",
      "sourceIp": "203.0.113.5",
      "userAgent": "Mozilla/5.0"
    },
    "requestId": "JKJaXmPLvHcESHA=",
    "routeKey": "GET /users/{userId}",
    "stage": "$default",
    "time": "12/Mar/2020:19:03:58 +0000",
    "timeEpoch": 1583348638390
  },
  "body": null,
  "isBase64Encoded": false
}

v1 vs. v2 Payload Format: Key Differences

FieldREST API (v1)HTTP API (v2)
Version markerNone (implicit v1)"version": "2.0"
HTTP methodhttpMethod (top-level)requestContext.http.method
Multi-value headersSeparate multiValueHeaders fieldComma-separated values in single headers map
Route inforesource fieldrouteKey field
CookiesIn headersSeparate top-level cookies array

Decision Flow: Which Integration Should You Use?

graph TD Start(["New API Gateway + Lambda Integration"]) Q1{"Do you need payload transformation at the gateway layer (VTL)?"} Q2{"Are you building a new greenfield API?"} Q3{"HTTP API or REST API?"} ProxyREST["REST API + Lambda Proxy Integration (v1 event format)"] ProxyHTTP["HTTP API + Lambda Integration (v2 payload format)"] Standard["REST API + Standard Integration (VTL templates required)"] Start --> Q1 Q1 -- "Yes" --> Standard Q1 -- "No" --> Q2 Q2 -- "Yes" --> Q3 Q2 -- "No (legacy)" --> ProxyREST Q3 -- "HTTP API (lower cost, lower latency)" --> ProxyHTTP Q3 -- "REST API (advanced features needed)" --> ProxyREST

Real-World Analogy

Think of API Gateway as a corporate mail room. With Proxy Integration, the mail room forwards the entire sealed envelope — stamp, return address, postmark, and all — directly to your desk. You open it and deal with everything yourself. With Standard Integration, the mail room opens the envelope, extracts only the relevant memo, reformats it onto a company letterhead, and then delivers it to you. On the way back out, they repackage your reply into the official corporate format before it leaves the building. More control, more process.

IAM & Security Considerations

Regardless of integration type, API Gateway requires permission to invoke your Lambda function. The resource-based policy on Lambda must grant lambda:InvokeFunction to the API Gateway service principal:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:us-east-1:123456789012:abc123/*/GET/users/*"
        }
      }
    }
  ]
}

The AWS:SourceArn condition scopes the permission to a specific API, stage, method, and resource path — following the principle of least privilege.

Common Pitfalls

  • Forgetting to stringify the body: Returning a JSON object (not a string) in the body field of a proxy response causes a 502.
  • Null vs. missing fields: queryStringParameters is null (not an empty object) when no query params are present. Always null-check before accessing keys.
  • Mixing v1 and v2 event shapes: If you migrate from REST API to HTTP API, your Lambda handler must be updated to read requestContext.http.method instead of top-level httpMethod.
  • CORS with proxy integration: Lambda is responsible for returning CORS headers (e.g., Access-Control-Allow-Origin) in every response, including error responses.

Wrap-Up & Next Steps

For the vast majority of modern serverless APIs, Lambda Proxy Integration is the right default — it eliminates VTL complexity, gives Lambda full HTTP control, and aligns with how frameworks like AWS SAM, Serverless Framework, and CDK generate API Gateway resources by default. Reserve Standard Integration for scenarios requiring strict payload transformation at the gateway layer without burdening Lambda.

Glossary

TermDefinition
Proxy IntegrationAPI Gateway passes the full HTTP request to Lambda as a structured event and returns Lambda's response directly to the client with no transformation.
Standard IntegrationAPI Gateway applies VTL mapping templates to transform both the request (before Lambda) and the response (before the client).
VTL (Velocity Template Language)A Java-based templating language used by API Gateway to define request/response mapping logic.
Payload Format VersionThe schema version of the event object sent to Lambda — v1.0 for REST APIs, v2.0 for HTTP APIs.
502 Bad GatewayThe HTTP error returned by API Gateway when Lambda's response does not conform to the expected proxy response structure.

Comments

Popular posts from this blog

EC2 No Internet Access in Custom VPC: Attaching an Internet Gateway and Fixing Route Tables

IAM User vs. IAM Role: Why Your EC2 Instance Should Never Use a User

Lambda Infinite Loop with S3: How to Prevent Recursive Triggers