Click or drag to resize
Pdf Library for .NET

Deployment to AWS Lambda

SelectPdf runs in AWS Lambda as a function packaged in a container image, on x86_64 and on arm64. A zip deployment is not possible: the Chromium engine and its libraries are larger than the 250 MB a zip-based function can hold.

The function and its image

Use the Lambda .NET base image and the packages for the function's architecture:

XML
<ItemGroup>
  <PackageReference Include="Amazon.Lambda.Core" Version="3.3.0" />
  <PackageReference Include="Amazon.Lambda.APIGatewayEvents" Version="3.0.1" />
  <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson"
                    Version="3.0.1" />
  <PackageReference Include="SelectPdf.Universal" Version="26.4.0" />
  <PackageReference Include="SelectPdf.Universal.Native.linux-x64"
                    Version="26.4.0" />
  <PackageReference Include="SelectPdf.Universal.Fonts" Version="26.4.0" />
</ItemGroup>
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish MyFunction.csproj -c Release -r linux-x64 \
    --self-contained false -o /app

FROM public.ecr.aws/lambda/dotnet:10
COPY --from=build /app ${LAMBDA_TASK_ROOT}
CMD ["MyFunction::MyFunction.Function::Handler"]

The function runs as Lambda's own non-root user; the native package makes the engine executable for every user when the image is built, so the Dockerfile needs no chmod. Lambda images have no fonts, which is why the fonts package is referenced.

A handler that converts the page given in the query string of a function URL or HTTP API request:

public APIGatewayHttpApiV2ProxyResponse Handler(
    APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context)
{
    HtmlToPdf converter = new HtmlToPdf();
    PdfDocument doc = converter.ConvertUrl(request.QueryStringParameters["url"]);
    byte[] pdf = doc.Save();
    doc.Close();
    return new APIGatewayHttpApiV2ProxyResponse
    {
        StatusCode = 200,
        Headers = new Dictionary<string, string> {
            ["Content-Type"] = "application/pdf" },
        Body = Convert.ToBase64String(pdf),
        IsBase64Encoded = true
    };
}
Step by step

You need the AWS CLI (aws configure) and Docker. The commands use region eu-north-1 and account 123456789012; replace both.

1. Build the image.--provenance=false --sbom=false matter: Lambda refuses the multi-manifest images Docker builds by default ("The image manifest, config or layer media type ... is not supported").

docker build --platform linux/amd64 --provenance=false --sbom=false \
    -t selectpdf-lambda .

2. Push it to Amazon ECR:

aws ecr create-repository --repository-name selectpdf-lambda
aws ecr get-login-password | docker login --username AWS \
    --password-stdin 123456789012.dkr.ecr.eu-north-1.amazonaws.com
docker tag selectpdf-lambda \
    123456789012.dkr.ecr.eu-north-1.amazonaws.com/selectpdf-lambda:1
docker push 123456789012.dkr.ecr.eu-north-1.amazonaws.com/selectpdf-lambda:1

3. Create an execution role - in the console, IAM > Roles > Create role > AWS service > Lambda, with the AWSLambdaBasicExecutionRole policy.

4. Create the function with 2048 MB of memory (Lambda gives processor time in proportion to memory) and a 120 second timeout:

IMAGE=123456789012.dkr.ecr.eu-north-1.amazonaws.com/selectpdf-lambda:1
aws lambda create-function --function-name selectpdf-lambda \
    --package-type Image --memory-size 2048 --timeout 120 \
    --code ImageUri=$IMAGE \
    --role arn:aws:iam::123456789012:role/selectpdf-lambda-role

5. Give it a URL (AWS_IAM requires signed requests; NONE makes it public):

aws lambda create-function-url-config --function-name selectpdf-lambda \
    --auth-type AWS_IAM

arm64 (Graviton): reference SelectPdf.Universal.Native.linux-arm64, publish with -r linux-arm64, build with --platform linux/arm64 and create the function with --architectures arm64. arm64 is cheaper per second and converts at a similar speed.

Response size

A Lambda response is limited to 6 MB and the PDF travels base64-encoded in it, so about 4.4 MB of PDF fits. Store larger documents in an Amazon S3 bucket and return a presigned link instead; the sample does this when its PDF_BUCKET environment variable names a bucket.

What to expect

Measured in October 2026 (eu-north-1, 2048 MB): every conversion succeeded on x86_64 and arm64, with every language rendered and the pages matching a Windows conversion. A warm function converts selectpdf.com in about 1.5 seconds (x86_64) to 2.3 seconds (arm64).

Lambda replaces an environment after a few idle minutes, and the first conversion of a new environment takes 10 to 50 seconds while Chromium starts. Provisioned concurrency keeps environments ready when that matters.

Sample

The official samples include this deployment, with a step-by-step README, in the cloud/aws-lambda folder of the edition's samples.

See Also