boxlang-aws-lambda
Use this skill when building, deploying, or debugging BoxLang applications on AWS Lambda — including Lambda.bx structure, handler conventions, environment variables, SAM CLI testing, performance optimization, connection pooling, multi-function routing, and the boxlang-starter-aws-lambda project.
BoxLang on AWS Lambda
Overview
The BoxLang AWS Runtime provides a pre-built Java handler for serverless Lambda functions. You write BoxLang classes; the runtime handles request/response lifecycle, serialization, logging, and error management.
Handler Configuration
Set this as your Lambda handler in AWS:
ortus.boxlang.runtime.aws.LambdaRunner::handleRequest
The runtime automatically:
- Deserializes the incoming JSON event into a BoxLang
Struct - Calls your
Lambda.bxclassrun()method - Serializes the return value back to JSON
- Manages error handling and logging
Lambda.bx Convention
The runtime looks for Lambda.bx in your deployment package root and calls run():
class {
/**
* The main Lambda handler function.
*
* @param event The incoming event struct (deserialized from JSON)
* @param context The AWS Lambda context object (Java LambdaContext)
* @param response A pre-built response struct you can populate:
* { statusCode: 200, body: "", headers: {} }
*/
function run( event, context, response ){
// Simple return value โ auto-serialized to JSON
return {
statusCode: 200,
body: {
message: "Hello from BoxLang Lambda!",
input: event
}
}
}
}
Response Convention
You can either return a value or populate the response struct:
function run( event, context, response ){
// Option 1: return a value (auto-serialized)
return { statusCode: 200, body: "OK" }
// Option 2: populate response struct
response.statusCode = 200
response.body = serializeJSON({ message: "Done" })
response.headers = { "Content-Type": "application/json" }
}
Application Lifecycle (Application.bx)
Place Application.bx in your deployment package for lifecycle hooks:
class {
this.name = "MyLambda"
// Called once on cold start โ initialize resources here
boolean function onApplicationStart(){
application.db = createObject("component","DataService").init()
return true
}
// Called on every request before run()
boolean function onRequestStart( required string targetPage ){
return true
}
}
Project Structure (Starter Template)
Use the official starter: https://github.com/ortus-boxlang/boxlang-starter-aws-lambda
/src
/main
/bx
Application.bx -- Lifecycle class
Lambda.bx -- Your Lambda handler
/resources
boxlang.json -- BoxLang runtime config
boxlang_modules/ -- Installed BoxLang modules
/test
/java
/com/myproject
LambdaRunnerTest.java -- Integration tests
TestContext.java
TestLogger.java
/workbench
config.env -- Default env config
config.local.env -- Local overrides (gitignored)
sampleEvents/ -- Test event payloads (.json files)
template.yml -- SAM template for local testing + deploy
*.sh -- Deploy/management scripts
/box.json -- BoxLang module dependencies
/build.gradle -- Build config (shaded JAR)
Environment Variables
| Variable | Description |
|---|---|
BOXLANG_LAMBDA_CLASS | Absolute path to Lambda class. Default: /var/task/Lambda.bx |
BOXLANG_LAMBDA_DEBUGMODE | Enable debug mode + performance metrics (true/false) |
BOXLANG_LAMBDA_CONFIG | Path to custom boxlang.json. Default: /var/task/boxlang.json |
BOXLANG_LAMBDA_CONNECTION_POOL_SIZE | Database connection pool size. Default: 2 |
LAMBDA_TASK_ROOT | Lambda deployment root. Default: /var/task |
Any BOXLANG_* env variable also maps to boxlang.json config overrides.
Performance Enhancements
Class Compilation Caching
Lambda classes are compiled and cached on the first (cold start) invocation. Warm invocations reuse the cached bytecode โ no re-compilation overhead.
Disable caching in development (debug mode):
BOXLANG_LAMBDA_DEBUGMODE=true
Connection Pooling
Database connections are pooled and reused across warm invocations:
BOXLANG_LAMBDA_CONNECTION_POOL_SIZE=5
Cold Start Optimization Tips
- Use
Application.bxonApplicationStart()to initialize shared resources - Minimize modules loaded at startup โ only install what you use
- Use the
asmcompiler (default) for better startup performance - Set
storeClassFilesOnDisk: trueinboxlang.json
Multiple Lambda Functions (URI Routing)
Use the x-bx-function header to call a specific method on the class:
# Calls Lambda.bx run() method (default)
curl https://api.example.com/function
# Calls Lambda.bx processOrder() method
curl -H "x-bx-function: processOrder" https://api.example.com/function
In Lambda.bx:
class {
function run( event, context, response ){
return { message: "Default handler" }
}
function processOrder( event, context, response ){
return orderService.process( event )
}
function getUsers( event, context, response ){
return userService.list( event.limit ?: 20 )
}
}
Local Development with SAM CLI
# Install AWS SAM CLI
# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html
# Start local Lambda API
sam local start-api --template workbench/template.yml
# Invoke a specific function locally
sam local invoke BoxLangFunction --event workbench/sampleEvents/test-event.json
# Build the shaded JAR (includes all dependencies)
./gradlew shadowJar
Deploying to AWS
# Configure AWS credentials first
aws configure
# Build, package, and deploy via SAM
./gradlew shadowJar
sam deploy --guided --template workbench/template.yml
# Or use the included deploy scripts
chmod +x workbench/*.sh
./workbench/deploy.sh
BoxLang Modules in Lambda
Install modules to the src/main/resources/boxlang_modules/ directory using CommandBox:
# Install a module to the Lambda module directory
box install bx-mail --boxlang-home=src/main/resources
# The module will be zipped with the deployment package
Production Checklist
-
Application.bxinitializes shared resources (connections, config) inonApplicationStart() -
BOXLANG_LAMBDA_DEBUGMODE=falsein production - Connection pool size tuned:
BOXLANG_LAMBDA_CONNECTION_POOL_SIZE - Secrets via AWS SSM Parameter Store or Secrets Manager, injected as env vars
-
boxlang.jsonpresent in deployment package root - Lambda timeout set generously for cold starts (30s+ recommended)
- Memory allocation โฅ 512MB (1024MB+ for better performance)
- Integration tests passing via
./gradlew test