Edge lambda functions
An Edge Lambda Function is a compute resource that runs your code at CDN edge locations, bringing it closer to your users to reduce latency and improve performance. These functions are globally distributed, ensuring that requests are handled by the nearest location.
Edge Lambdas are serverless, which means Stacktape manages the infrastructure, security, and scaling for you. They support Node.js and Python runtimes and follow a pay-per-use model, so you only pay for the execution time you consume.
Common use cases include user authentication, request validation, and cookie manipulation.
Under the hood
Stacktape uses Lambda@Edge to power Edge Lambda Functions. These functions are associated with a CDN and are triggered by CDN events—either when a request is made to the CDN (onRequest) or when the CDN is about to send a response back to the user (onResponse).
When to use
Advantages
- Low latency: By executing code closer to the end-user, you can significantly improve your application's performance.
- Scalability: Edge Lambdas automatically scale with the number of incoming requests.
- Pay-per-use: You are billed only for the compute time you use, measured in milliseconds.
Disadvantages
- Limited execution environment: Edge lambdas triggered by
onRequestoronResponseevents are limited to 128MB of memory and a 5-second maximum execution time.
Basic usage
You can associate an edge-lambda-function with the CDN to be executed at different stages:
onRequest: Executed when the CDN receives a request from a client, before checking the cache.onResponse: Executed before returning a response to the client.
Potential Use Cases:
- Generating an immediate HTTP response without checking the cache or forwarding to the origin.
- Modifying the request (e.g., rewriting the URL or headers) before forwarding to the origin.
- Inspecting cookies or validating authorization headers and tokens.
In the following example, an Edge Lambda Function validates the Authorization header of each incoming request. If the header is missing or invalid, the user is redirected to a login page.
resources:authFunction:type: edge-lambda-functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: auth-function.tsmyBucket:type: bucketproperties:cdn:enabled: trueedgeFunctions:onRequest: authFunction
const validateAuthorizationToken = (token) => {// perform some validationreturn true;};export default async (event) => {const { request } = event.Records[0].cf;const { headers } = request;const authorizationToken = headers.authorization?.[0]?.value;const userAuthorized = validateAuthorizationToken(authorizationToken);// if user is not authorized, redirect him to login pageif (!userAuthorized) {return {status: '302',headers: {location: [{key: 'Location',value: '/login'}],'cache-control': [{key: 'Cache-Control',value: 'no-cache, no-store, max-age=0, must-revalidate'}]}};}// after we validated that user is authorized, we can return the request// request will be forwarded to originreturn request;};
Code of the authFunction authorizer.
Event structure
The event payload delivered to your function depends on the trigger:
On request trigger
When a function is triggered by an onRequest event, you can either:
- Return a response directly from the function: This bypasses the origin and serves the response immediately to the client.
- Modify the request and forward it to the origin: You can alter the request (e.g., add headers) before it continues to the origin.
The following example demonstrates both:
const validateAuthorizationToken = (token) => {// perform some validationreturn true;};export default async (event) => {const { request } = event.Records[0].cf;const { headers } = request;const authorizationToken = headers.authorization?.[0]?.value;const userAuthorized = validateAuthorizationToken(authorizationToken);// if user is not authorized, redirect him to login pageif (!userAuthorized) {return {status: '302',headers: {location: [{key: 'Location',value: '/login'}],'cache-control': [{key: 'Cache-Control',value: 'no-cache, no-store, max-age=0, must-revalidate'}]}};}// after we validated that user is authorized, we can return the request// request will be forwarded to originreturn request;};
If the user is authorized, the request is forwarded to the origin. Otherwise, a redirect response is returned.
resources:authFunction:type: edge-lambda-functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: auth-function.tsmyBucket:type: bucketproperties:cdn:enabled: trueedgeFunctions:onRequest: authFunction
Example configuration for the authorizer function.
On response trigger
A function triggered by an onResponse event can modify the response from the origin before it's sent to the client. In this example, the function adds a Set-Cookie header to the response:
export default async (event) => {const { response } = event.Records[0].cf;response.headers['set-cookie'] = [{key: 'Set-Cookie',value: 'my-experimental-cookie=cookie-value'}];return response;};
Code for the function that sets a cookie.
resources:cookieFunction:type: edge-lambda-functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: set-cookie.tsmyBucket:type: bucketproperties:cdn:enabled: trueedgeFunctions:onResponse: cookieFunction
Example configuration for the onResponse trigger.
Packaging
Packaging for Edge Lambda Functions follows the same process as for regular Lambda functions. For more details, see the packaging documentation.
For functions triggered by onRequest or onResponse, the zipped package size cannot exceed 1MB.
Logging
Function logs (stdout and stderr) are sent to CloudWatch log groups.
Important: Since Edge Lambda functions run in multiple AWS regions, logs are delivered to a log group in the region where the function was executed.
You can use the stacktape stack-info command to get links to the log groups in each region.
Accessing other resources
By default, Edge Lambda Functions cannot access other AWS resources. Permissions must be granted explicitly using IAM. Stacktape automatically handles permissions for essential services like logging.
You can grant additional permissions in two ways:
Using connectTo
The connectTo property simplifies granting access to other Stacktape-managed resources. It automatically configures the necessary IAM permissions and injects environment variables with connection details.
resources:authFunction:type: edge-lambda-functionproperties:packaging:type: stacktape-lambda-buildpackproperties:entryfilePath: auth-function.tsconnectTo:# access to the dynamo table- myDynamoTable# access to AWS SES- aws:sesmyDynamoTable:type: dynamo-db-tableproperties:primaryKey:partitionKey:name: idtype: string
By listing resources here, Stacktape automatically configures the necessary IAM permissions and security group rules. It also injects environment variables with connection details into the function's runtime.
Note: Environment variable injection is not supported for Edge Lambda functions. Also, Edge Lambda functions cannot connect to resources within a VPC.
Supported Resources:
- Bucket: Grants permissions to list, create, get, and delete objects.
- DynamoDB table: Grants permissions for item manipulation and table scanning/querying.
- MongoDB Atlas cluster: Allows secure, credential-less access to the cluster.
- Relational database: Allows connections to the database.
- Redis cluster: Allows connections to the Redis cluster.
- Event bus: Grants permission to publish events.
- Function: Grants permission to invoke another function.
- Batch job: Grants permissions to manage batch jobs.
- User auth pool: Grants full control over a Cognito User Pool.
- Upstash Kafka topic: Provides connection details.
- Upstash Redis: Provides connection details.
- aws:ses: Grants full permissions to Amazon Simple Email Service (SES).
Using iamRoleStatements
For more granular control, you can provide raw IAM role statements to define custom permissions.
Be mindful of latency when accessing other resources. While your stack is deployed in a specific region, your Edge Lambda may execute in a different edge location across the globe, which can increase the time it takes to communicate with your other resources.