The Dev Quill

The Dev Quill

Share this post

The Dev Quill
The Dev Quill
Lambda Function URLs: An Overview

Lambda Function URLs: An Overview

What are they good for? How much will it cost? And are there alternatives?

Jimmy Wei's avatar
Jimmy Wei
Oct 06, 2024

Share this post

The Dev Quill
The Dev Quill
Lambda Function URLs: An Overview
Share

Introduction to Lambda Function URLs

Lambda Function URLs landed in April 2022. In many ways they provided a simpler solution to an already solved problem. Everything that can be done with Lambda Function URLs, even to this day, can be achieved through using a public API Gateway.

So what’s the big deal with them?

Well, having an API Gateway is an overhead. Especially if it’s just for a couple of targets sitting behind it. Every request that comes through the API Gateway is billable. And it’s not cheap either.

The current going rate as of time of writing is $3.50/million requests. Yes, there’s no upfront costs, but this is one of the few AWS services based around HTTP that make a flat charge. Most services take into account the duration and computation involved. But in this case, a 1KB payload is no different to a 1GB payload entering the system.

To put this in perspective, the cost per request (“invocation”) for a standard Lambda Function in London (EU-WEST-2) is $0.20/million requests. That’s nearly a 18 fold difference for the same request.

A popular site in the UK, Cinch, are reported to have up to 4.5 million requests per day- that’s nearly 135 million requests a month1, which works out at a $472/month overhead.

Assuming every hour 1GB gets consumed (much higher than your average typical request), using an Application Load Balancer would cost under the $50 mark comfortably.

Of course, we can’t assume to be able to swap out services on a 1-1 basis given the use case, but it really does put an expensive sticker tag on the API Gateway if you’re not fully utilising the capabilities it offers.

Use Cases

So what are the tradeoffs then? It seems like an 18 fold difference would always come with some, otherwise everyone would be using this new tech as a no-brainer.

Lambda Function URLs can’t (in comparison to API Gateway):

  • Rate limit users based on identity

  • Sit behind a WAF (Web Application Firewall) directly

  • No custom domain - once deployed, you’re stuck with a randomly generated URL forever

  • Have advanced monitoring (request latency, data transfer metrics)

  • Restricted to one endpoint per lambda function

These limitations mean that there are specific use cases, for instance:

  • Webhooks connecting to your inner AWS services

  • Internal tooling to trigger a CRUD action

  • Prototyping

Cost Comparison

To do any kind of black and white comparison like this, we’ll have to make a few assumptions:

  • 5 million requests

  • 128MB assigned memory in US East (N. Virginia)

  • An average invocation times of 50ms

  • Ignoring data egress costs

API Gateway + Lambda

Lambda: $1.53/month
API Gateway: $17.50/month ($3.50/million request)

Total Costs: $19.03/month

Lambda Function URLs

Lambda: $1.53/month

Total Costs: $1.53/month

That represents 12x cost difference between the two architectures.

Of course, the more requests you have going through, the cheaper it gets both for the API Gateway + Lambda. But for the majority of use cases where Lambda Function URLs are applicable for, it seems unreasonably expensive.

URL Anatomy and The Public Internet

When a Lambda Function URL gets deployed, you get a URL that is associated with that Lambda function.

It looks like this:

  • https://<RANDOM-ID>.lambda-url.<REGION>.on.aws

The random ID (<RANDOM-ID>) is determined on the initial deployment, and the region (<REGION>) is the region in which the function is deployed in.

All deployed URLs will be using the https protocol. This is something that’s not configurable.

Using Serverless Framework to handle our infrastructure as code

// serverless.yml

service: lambda-urls-demo

provider:
  name: aws
  stage: dev
  region: eu-west-2

functions:
  test:
    handler: handler.demoHandler
    url: true
/*
  handler.js
 */
function demoHandler(event) {
	return {
		statusCode: 200
    }
}

module.exports = {
	demoHandler
}

Running: serverless deploy --aws-profile PROFILE

Deploying lambda-urls-demo to stage dev (eu-west-2)

✔ Service deployed to stack lambda-urls-demo-dev (34s)

endpoint: https://v2olvkdtht02sy5utbvzshbcei0szimt.lambda-url.eu-west-2.on.aws/
functions:
  test: lambda-urls-demo-dev-test (1.9 kB)

Observe the endpoint exposed, notice how it’s set to HTTPS. By design these accessible on the public internet.

There isn’t any way to associate the Lambda Function URL to a private VPC. If this is a deal breaker, then naturally Lambda Function URLs aren’t the correct choice for your architecture.

Securing Lambda Function URLs

Lambda Function URLs allow you to set the authentication type. This can either be configured as AWS_IAM or NONE.

AWS_IAM is a good default choice. This allows delegating authorisation to the AWS IAM service.

However there are “gotchas” with this, the main one being how one actually calls the Lambda Function URL when this is set.

// serverless.yml

service: lambda-urls-demo

provider:
  name: aws
  stage: dev
  region: eu-west-2

functions:
  test:
    handler: handler.demoHandler
    url:
      authorizer: aws_iam # Enables AWS_IAM authorization

With AWS_IAM enabled, this requires the request made to be pre-signed before sending out the request.

The simplest way to verify that it works without worrying about how to implement signature generations is via docker using a tool called awscurl.

docker run --rm -it okigan/awscurl 
  --access_key ACCESS_KEY 
  --secret_key SECRET_KEY 
  --region REGION 
  --service lambda 
  www.12345.lambda-url.eu-west-2.on.aws

What actually happens when you call this is the following:

  • Request payload gets pre-signed with your AWS credentials

  • That pre-signed signature gets put into the header of the request

  • AWS receives the request, then calculates the expected signature of their end

  • AWS matches their expected signature, with the one provided in the header (from step 2)

  • If the signatures don’t match, the request gets rejected

'Fire-walling' your Lambda Function URL

Lambda Function URLs contain the user’s IP address in the event payload. We can use this to further enhance the security of our lambda function.

/*
  handler.js
 */
function demoHandler(event) {
	const clientIpAddress = event["headers"]["x-forwarded-for"];

	const whitelistedIps = [
		"133.33.33.7"
	];
	if (!whitelistedIps.includes(clientIpAddress)) {
		return {
			statusCode: 401
		}
	}

	return {
		statusCode: 200
	}
}

module.exports = {
	demoHandler
}

We can observe the event’s x-forwarded-ip header which will reveal the requestor’s public IP address. If our the whitelisted IP doesn’t match, we can reject the request within the application code. This may be more suitable if the consumer doesn’t have an IAM user.

We could take this a step further by involving a stateful database to manage these IPs such as DynamoDB. The tradeoff being you have the overhead of managing whitelisted IP addresses.

Retrieving the AWS_IAM user identity

We can also retrieve within the event payload who made the request, if we opt in for the AWS_IAM authentication mode.

This may be useful for auditing purposes or for other reasons downstream in the application that requires the identity of the caller.

function demoHandler(event) {
	const userArn = event["requestContext"]["authorizer"]["iam"]["userArn"];
	console.log(userArn); // arn:aws:iam::XXXXXXXXXXXX:USER

	console.log(JSON.stringify(event["requestContext"]));
	/*
        "accountId": "390901917839",
        "apiId": "v2olvkdtht72sy4utbvvshbcwi0szimt",
        "authorizer": {
            "iam": {
                "accessKey": "XYZ",
                "accountId": "XXXXXXXXXXXX",
                "callerId": "XXXXXXXXXXXX",
                "cognitoIdentity": null,
                "principalOrgId": "o-1YYYYYYYY",
                "userArn": "arn:aws:iam::XXXXXXXXXXXX:USER",
                "userId": "XXXXXXXXXXXX"
            }
        },
        "domainName": "v2olvkdtht02sy5utbvzshbcei0szimt.lambda-url.eu-west-2.on.aws",
        "domainPrefix": "v2olvkdtht02sy5utbvzshbcei0szimt",
        "http": {
            "method": "GET",
            "path": "/",
            "protocol": "HTTP/1.1",
            "sourceIp": "185.241.227.234",
            "userAgent": "python-requests/2.30.0"
        },
        "requestId": "89381aa6-0d46-4cd5-8b2e-8f7c7f6c223b",
        "routeKey": "$default",
        "stage": "$default",
        "time": "23/May/2023:20:29:39 +0000",
        "timeEpoch": 1684873779193
     */

	return {
		statusCode: 200
	}
}

module.exports = {
	demoHandler
}

Conclusion

Lambda Function URLs offers an opportunity of major cost savings and the ability to get started as soon as possible.

It's never been faster to deploy out a piece of business logic to the public internet before, but with this comes with the right use cases.

Webhooks are without a doubt the best candidate for this, they are typically event driven and applications typically authenticate through access tokens or API Keys.

API Gateway can also offer this natively, but at the overhead cost of the managing the API Gateway is overkill.

Single function microservices that permit transiting data over the public internet may also be the right choice here.

However, any microservice that has multiple functions involved would result in multiple URLs to manage. This may add extra overhead in the long run, so is not advisable. The API Gateway abstracts this through stages under the same rest API ID, i.e www.<rest-id>.apigateway.aws.com/<stage>/url-1.

Finally, sensitive data that should flow within a private VPC would not be suitable here. A private API gateway would be more appropriate through configuring the lambda function to be attached to the private VPC.

1

https://aws.amazon.com/blogs/startups/scale-your-startup-with-serverless-on-aws

Share this post

The Dev Quill
The Dev Quill
Lambda Function URLs: An Overview
Share
© 2025 Jimmy Wei
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share