Lambda Function URLs are a surprisingly simple way to expose your Lambda functions directly over HTTP without the overhead and complexity of API Gateway.
Let’s see this in action. Imagine you have a simple Lambda function written in Python that just returns a greeting.
import json
def lambda_handler(event, context):
name = event.get('name', 'World')
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json'
},
'body': json.dumps({'message': f'Hello, {name}!'})
}
You can create a Function URL for this with a single command in the AWS CLI:
aws lambda create-function-url-config \
--function-name my-greeting-function \
--auth-type AWS_IAM \
--invoke-mode BUFFERED
This command creates a unique HTTPS endpoint for your function. AWS_IAM means you’ll authenticate requests using AWS credentials, which is great for internal services or scripts. If you want to make it publicly accessible (use with caution!), you’d use --auth-type NONE. BUFFERED is the default and suitable for most synchronous invocations.
Once created, AWS will provide you with a URL like https://<url-id>.lambda-url.<region>.on.aws/. You can then curl this endpoint, passing your AWS credentials in the Authorization header.
curl -X POST \
-H "Authorization: AWS4-HMAC-SHA256 Creds=<YOUR_ACCESS_KEY_ID>/<DATE>/<REGION>/lambda/aws4_request,SignedHeaders=host;x-amz-date,Signature=<YOUR_SIGNATURE>" \
https://<url-id>.lambda-url.<region>.on.aws/ \
-d '{"name": "Alice"}'
The response will be:
{"message": "Hello, Alice!"}
This bypasses API Gateway entirely. When a request hits the Function URL, Lambda directly invokes your function, passing the HTTP request details (headers, body, query parameters, path parameters) within the event object. The response dictionary your function returns is then mapped back to an HTTP response. statusCode becomes the HTTP status code, headers populate the response headers, and body becomes the response body.
The primary problem Lambda Function URLs solve is providing a simple, low-latency, and cost-effective way to expose HTTP endpoints for event-driven applications, microservices, or even simple webhooks. Think of scenarios where you don’t need the advanced routing, request transformation, or authorizer capabilities of API Gateway. For instance, a simple webhook receiver for a GitHub event or a backend for a single-page application that performs basic data retrieval.
The invoke-mode parameter is worth noting. While BUFFERED (the default) is good for most cases, RESPONSE_STREAM allows for streaming responses directly from your Lambda function. This is particularly useful for large payloads or long-running operations where you want to start sending data back to the client before the entire Lambda execution is complete, improving perceived latency.
The auth-type is critical for security. AWS_IAM requires clients to sign their requests with AWS credentials, ensuring that only authenticated and authorized callers can invoke your function. NONE makes the endpoint public, meaning anyone with the URL can invoke it, which is suitable for truly public-facing services but requires careful consideration of your function’s logic to prevent abuse. You can also configure CORS directly on the Function URL resource, simplifying cross-origin requests from web browsers.
When you configure a Function URL, Lambda automatically creates a resource-based policy that grants invocation permission to the principal associated with the authentication type. For AWS_IAM, this means principals that can lambda:InvokeFunctionUrl on the specific function URL resource. For NONE, it grants permission to everyone.
Under the hood, the Function URL is a managed endpoint that directly integrates with the Lambda invocation service. Unlike API Gateway, which acts as a full-fledged HTTP proxy, the Function URL is a more direct, lightweight path. This direct integration means less network hops and reduced latency, especially for simple request-response patterns. The request payload is structured within the event object, and the response structure is strictly defined. If your function returns a dictionary that doesn’t conform to the expected HTTP response format (e.g., missing statusCode or body), Lambda will return a 502 Bad Gateway error.
The maximum payload size for Function URLs is 6MB for synchronous invocations and 30MB for asynchronous invocations when using BUFFERED mode. For RESPONSE_STREAM mode, the maximum payload size is 75MB.
The next logical step after exposing your function is handling more complex routing or authentication needs, which might lead you back to exploring API Gateway.