Until this year, giving a Lambda function an HTTP endpoint meant adding API Gateway or an Application Load Balancer. Since April 2022, a function can have a built-in function URL: a dedicated HTTPS endpoint of the form https://<url-id>.lambda-url.<region>.on.aws, with no extra service to configure and no per-request API Gateway charge (you pay for the Lambda invocations).
Versions in use on this date. Python 3.9 on Lambda and AWS CLI 2.7. Function URLs support two authorization modes (NONE and AWS_IAM), CORS configuration, and the same request and response payload format as API Gateway HTTP APIs (version 2.0).
Request path
flowchart TB
C[Client] -->|HTTPS| FU[Function URL<br/>https id lambda-url ap-south-1 on.aws]
FU --> AUTH{Auth type}
AUTH -->|AWS_IAM| SIG[Requires SigV4 signed request<br/>caller needs lambda InvokeFunctionUrl]
AUTH -->|NONE| PUB[Open to the internet<br/>app must authenticate]
SIG --> FN
PUB --> FN[Lambda function handler]
FN --> DB[(DynamoDB, S3, RDS)]
FN --> RESP[Response JSON status headers body]
RESP --> C
FN -.-> CW[CloudWatch Logs and metrics]
Create a function and URL
# lambda_function.py
import json
def lambda_handler(event, context):
method = event["requestContext"]["http"]["method"]
path = event["rawPath"]
body = json.loads(event["body"]) if event.get("body") else {}
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"method": method, "path": path, "echo": body}),
}
zip fn.zip lambda_function.py
aws iam create-role --role-name hello-fn-role --assume-role-policy-document file://lambda-trust.json
aws iam attach-role-policy --role-name hello-fn-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws lambda create-function --function-name hello-url --runtime python3.9 --handler lambda_function.lambda_handler \
--zip-file fileb://fn.zip --role arn:aws:iam::111111111111:role/hello-fn-role --timeout 10 --memory-size 256
aws lambda create-function-url-config --function-name hello-url --auth-type AWS_IAM \
--cors 'AllowOrigins=https://app.example.com,AllowMethods=GET,POST,AllowHeaders=content-type,MaxAge=3600'
aws lambda get-function-url-config --function-name hello-url
The output includes FunctionUrl. With AWS_IAM, you must sign requests:
curl --aws-sigv4 "aws:amz:ap-south-1:lambda" --user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
-H "x-amz-security-token: $AWS_SESSION_TOKEN" -H "content-type: application/json" \
-d '{"hello":"world"}' https://abcd1234.lambda-url.ap-south-1.on.aws/test
(--aws-sigv4 needs curl 7.75 or newer.) Allow a specific role to call it:
aws lambda add-permission --function-name hello-url --statement-id invoke-url \
--action lambda:InvokeFunctionUrl --principal arn:aws:iam::111111111111:role/client-role \
--function-url-auth-type AWS_IAM
Public endpoints (NONE)
aws lambda create-function-url-config --function-name hello-public --auth-type NONE
aws lambda add-permission --function-name hello-public --statement-id public-url \
--action lambda:InvokeFunctionUrl --principal "*" --function-url-auth-type NONE
NONE means anyone can call it. Only use it when the function authenticates callers itself (a signed webhook secret, a JWT it validates) or the data is public. Add input validation, rate awareness and logging, because there is no WAF, throttling plan or API key in front.
Function URL, API Gateway or ALB?
| Need | Function URL | API Gateway (HTTP/REST) | ALB |
|---|---|---|---|
| Simple endpoint, webhooks, internal tools | Best | More than needed | More than needed |
| Custom domain with your TLS certificate | No (put CloudFront in front) | Yes | Yes |
| Usage plans, API keys, request validation, throttling per client | No | Yes (REST API) | No |
| JWT/Cognito authorizers | No (do in code) | Yes | Via OIDC action |
| WAF integration | Via CloudFront | Yes | Yes |
| Multiple routes mapped to many functions | One function handles all routes | Yes | Path rules |
| Cost | Lambda only | + per-request charge | + hourly and LCU |
For a custom domain on a function URL, front it with CloudFront (with an origin access control or custom header the function checks), which also gives caching and WAF.
Operational notes
- Concurrency and throttling: set reserved concurrency to cap cost and protect downstream systems, and alert on
Throttles,ErrorsandDurationmetrics. - Timeouts: the function URL allows up to the function’s timeout (maximum 15 minutes), but clients and proxies usually give up sooner.
- Payload limits: 6 MB request and response (synchronous invocation limit).
- Logging: log the request ID, path and status; do not log whole bodies containing personal data.
- Infrastructure as code: CloudFormation
AWS::Lambda::Url, Terraformaws_lambda_function_url, and the permission resource, so the setting is reviewed and repeatable. - Delete unused URLs:
aws lambda delete-function-url-config --function-name hello-public; an open public URL on a forgotten function is an easy target.