Skip to main content

Serve — Lambda Web Adapter

Deploy a Rank HTTP app to AWS Lambda using the Lambda Web Adapter and a provided.al2023 custom runtime — no container image required.

The adapter is attached as a Lambda Layer. It translates Lambda invocations into HTTP requests forwarded to rank serve, so the Rank app needs no Lambda-specific handler code.

Source

examples/serve-lambda/main.rank
use std::HTTP
use std::Runtime

HealthRoute = HTTP::Route {
method: `GET`,
path: `/health`
}

Routes = HealthRoute

pub config = {
defaultResponseFormat: `json`
}

pub main = |req: Runtime::ExecutionContext<Routes>| -> HTTP::Response {
return {
status: 200,
body: {
ok: true,
service: `serve-lambda-web-adapter-example`
}
}
}
examples/serve-lambda/bootstrap
#!/bin/sh
export PATH="$LAMBDA_TASK_ROOT/bin:$LAMBDA_TASK_ROOT/node_modules/.bin:$PATH"
exec rank serve "$LAMBDA_TASK_ROOT" --host 0.0.0.0 --port "${PORT:-8080}"
examples/serve-lambda/Makefile
.PHONY: build-RankApp

build-RankApp:
dnf install -y nodejs npm 2>/dev/null || true
npm install --prefix "$(ARTIFACTS_DIR)" @rank-lang/cli
"$(ARTIFACTS_DIR)/node_modules/.bin/rank" sync .
cp main.rank rank.toml "$(ARTIFACTS_DIR)/"
cp bootstrap "$(ARTIFACTS_DIR)/"
chmod +x "$(ARTIFACTS_DIR)/bootstrap"
mkdir -p "$(ARTIFACTS_DIR)/bin"
cp "$$(which node)" "$(ARTIFACTS_DIR)/bin/"
examples/serve-lambda/template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Globals:
Function:
Timeout: 30
MemorySize: 512

Resources:
RankApp:
Type: AWS::Serverless::Function
Properties:
Runtime: provided.al2023
Architectures:
- x86_64
Handler: bootstrap
CodeUri: ./
Layers:
- !Sub arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:24
Environment:
Variables:
PORT: '8080'
READINESS_CHECK_PATH: /.well-known/rank/ready
Events:
Api:
Type: HttpApi
Properties:
Path: /{proxy+}
Method: ANY
RootApi:
Type: HttpApi
Properties:
Path: /
Method: ANY
Metadata:
BuildMethod: makefile

Outputs:
ApiUrl:
Description: API Gateway endpoint
Value: !Sub https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com

Build and deploy

Requires the AWS SAM CLI. Docker is used only for the SAM container build step, not the Lambda runtime.

There is no separate Rank compile step for this example. The Lambda source bundle is the example directory itself:

  • main.rank is the Rank app source.
  • rank.toml makes the directory runnable as rank serve ..
  • bootstrap is the custom runtime entrypoint Lambda executes.
  • template.yaml tells SAM to build the function with the local Makefile via BuildMethod: makefile.

Run the build from examples/serve-lambda:

cd examples/serve-lambda

# Build inside an Amazon Linux 2023 container so node matches the runtime
sam build --use-container

# First deploy (creates samconfig.toml)
sam deploy --guided

During sam build, SAM invokes the build-RankApp target from Makefile inside the AL2023 build container. The target name is build-<LogicalId>, so it matches the function resource name RankApp in template.yaml. SAM also sets ARTIFACTS_DIR to the staging directory that will become the Lambda bundle.

That target:

  1. Installs Node.js via dnf
  2. Installs @rank-lang/cli into the artifact directory
  3. Runs rank sync . to pre-cache registry dependencies
  4. Copies main.rank, rank.toml, and bootstrap into the Lambda artifact directory
  5. Copies the node binary so it is available at $LAMBDA_TASK_ROOT/bin/node at runtime

After the build, the staged Lambda bundle is under .aws-sam/build/RankApp/. That directory is what SAM deploys to Lambda.

Test it

curl https://<api-id>.execute-api.<region>.amazonaws.com/health
{
"ok": true,
"service": "serve-lambda-web-adapter-example"
}

Local testing without Lambda:

rank serve . --host 127.0.0.1 --port 8080

Or with the SAM local emulator:

sam local start-api --port 8080

Key concepts

  • Runtime: provided.al2023 — Lambda calls the bootstrap executable directly. No managed runtime is involved; rank serve is the only process.
  • Lambda Web Adapter layer — the LambdaAdapterLayerX86 layer adds an extension that translates Lambda invocations into HTTP requests and forwards them to the server on PORT.
  • PORT=8080 — the adapter forwards traffic to rank serve on this port.
  • READINESS_CHECK_PATH=/.well-known/rank/ready — the adapter polls this built-in endpoint on startup and withholds traffic until rank serve is ready to accept connections.
  • rank sync . at build time — caches registry dependencies so cold starts don't need outbound package requests.
  • No Lambda handler — the Rank app is unaware it runs on Lambda. The same rank serve command works locally and behind the adapter.