# swift-aws-lambda-runtime: a Swift client for the AWS Lambda Runtime API

> The awslabs package implements the AWS Lambda Runtime API in Swift on top of SwiftNIO, and gives you a layered API ranging from closures to streaming and background task handlers. The tooling is unusually complete, with SPM plugins for scaffolding, building and deploying, but the package is still an incubated experiment rather than a supported runtime.

**awslabs/swift-aws-lambda-runtime** — Swift implementation of AWS Lambda Runtime

- Repository: https://github.com/awslabs/swift-aws-lambda-runtime
- Website: https://swiftpackageindex.com/awslabs/swift-aws-lambda-runtime
- Stars: 1,236 · Forks: 114
- Language: Swift
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/awslabs-swift-aws-lambda-runtime

## The gap this package fills for a Swift service

AWS Lambda functions run behind a specific contract. Your code is not a web server: the platform hands you an event, expects a response within a limit, and reuses the execution environment across invocations. A managed runtime hides that contract behind a language specific SDK. A custom runtime means your artefact has to speak the Runtime API protocol itself, polling for the next event, returning a result, and answering the platform's health and error requests.

This package is a Swift implementation of that Runtime API, and it exists so a Swift service can run as a Lambda function without writing an HTTP polling client from scratch. The intended reader is a backend team that already works in Swift, on Apple platforms or in server side Swift, and now needs one function to run as a serverless function rather than as a long lived service.

The README's own description is worth quoting because it explains the shape of the API. It uses an embedded asynchronous HTTP client based on SwiftNIO, and it provides a layered API for building a range of Lambda functions, from simple closures to complex, performance-sensitive event handlers. Two things follow from that. First, the NIO base means the runtime client is not a blocking wrapper around the platform, it is an event loop, which is what makes streaming and background work plausible rather than bolted on. Second, the layered API means you start with a closure and drop down a level when you need control, instead of rewriting your handler when a simple case becomes a special one.

## What the repository contains beyond the runtime library

The tree is larger than a typical client library, and the reason is that the hard part of a custom runtime is not the protocol.

`Sources/` holds the library, `Tests/` the test suite, and `Plugins/` the Swift Package Manager plugins that do the scaffolding, building and deployment. `Examples/` contains complete runnable functions, and the list is a good map of what the runtime supports: `HelloJSON`, `HelloWorld`, `HelloWorldNoTraits`, `APIGatewayV1`, `APIGatewayV2`, `APIGatewayV2+LambdaAuthorizer`, `MultiSourceAPI`, `MultiTenant`, `Streaming+APIGateway`, `Streaming+Codable`, `Streaming+FunctionUrl`, `BackgroundTasks`, `ServiceLifecycle+Postgres`, `ManagedInstances`, `ResourcesPackaging`, `S3EventNotifier`, `S3_AWSSDK`, `S3_Soto`, `OCIImage`, `JSONLogging`, `HummingbirdLambda`, `CDK`, `Testing` and `Tutorial`.

Read that list as a capability map. There is a dedicated example for each service integration, one for the Swift Service Lifecycle integration with PostgreSQL, and three separate streaming examples, which tells you streaming is a first-class path rather than an afterthought. The `HelloWorldNoTraits` example alongside `HelloWorld` suggests the traits based API is optional, and `HummingbirdLambda` is another integration example.

There is also `Package.swift`, `Makefile`, `CONTRIBUTING.md`, `SECURITY.md`, `NOTICE.txt` and a `projects.md`. The Makefile is more than a convenience wrapper. It has a `format` target built on `swift format`, a `generate-docs` target that temporarily injects the swift-docc-plugin into `Package.swift` and then restores the original file, and Docker based test targets that run the compilation and test suite on Linux across Swift toolchains, with an isolated scratch path per target so the Linux build products do not collide with the local macOS `.build` directory.

## Adding the package and scaffolding the first function

The prerequisites are specific: the Swift 6.x toolchain, Docker (or Apple container) to build for Amazon Linux, and the AWS CLI configured with `aws configure`. On macOS the README asks for macOS 15 (Sequoia) or later.

The first step creates an executable package and wires the runtime into it:

```bash
mkdir MyLambda && cd MyLambda
swift package init --type executable --name MyLambda
swift package add-dependency https://github.com/awslabs/swift-aws-lambda-runtime.git --from 3.0.0
swift package add-target-dependency AWSLambdaRuntime MyLambda --package swift-aws-lambda-runtime
```

Note the version floor in that command, `--from 3.0.0`. The package publishes 3.0.0, 3.0.1 and 3.0.2 in September 2026, and the 3.x line is a major version, so a dependency declared below it is a different API.

Scaffolding is then a plugin invocation rather than a file you copy by hand:

```bash
swift package lambda-init --allow-writing-to-package-directory
```

The plugin generates a starting point in `Sources/MyLambda/MyLambda.swift`. The `--allow-writing-to-package-directory` flag exists because a package manager command that modifies the package directory is treated as a write to a location the user did not explicitly name, so the flag is the deliberate consent step. If you omit it, the plugin should refuse to write.

That two step arrangement is a genuine design choice rather than an accident. The first command describes what the package depends on, the second generates code that matches the version already in your dependency graph. It also means the scaffold can be regenerated after an upgrade instead of being copied once and drifting.

## Writing the handler and invoking it on port 7000

The generated handler is a closure that takes a decoded event and a context, and returns an encodable response:

```swift
import AWSLambdaRuntime

struct HelloRequest: Decodable {
    let name: String
    let age: Int
}

struct HelloResponse: Encodable {
    let greetings: String
}

let runtime = LambdaRuntime {
    (event: HelloRequest, context: LambdaContext) in
    HelloResponse(
        greetings: "Hello \(event.name). You look \(event.age > 30 ? "younger" : "older") than your age."
    )
}

try await runtime.run()
```

The shape is the point. `Decodable` and `Encodable` do the JSON work, so the handler deals in typed Swift values and the runtime deals in the wire format. `LambdaContext` is passed alongside the event for request metadata. `try await runtime.run()` is the entry point, and the handler is written as an async closure, which is what lets a later layer add streaming or background behaviour without changing the call site.

Local testing needs no AWS account. Running the executable starts a local server on port 7000 that speaks the same invoke protocol:

```bash
swift run &
curl --header "Content-Type: application/json" \
     --data '{"name":"World","age":30}' \
     http://127.0.0.1:7000/invoke
```

The request goes to `/invoke` on the loopback address with a JSON content type and the same payload you would later send to the deployed function. That symmetry is what makes the local loop useful: the request you test is the request you deploy, rather than a test harness that behaves differently from production. The `Testing` example in the tree suggests the same idea is taken further for automated tests.

## Building for Amazon Linux in a container, then deploying

Lambda runs your function on Amazon Linux, so a binary built on macOS is not the artefact you deploy. The package handles that with two plugin commands, one to build and one to deploy:

```bash
swift package --allow-network-connections docker lambda-build
swift package --allow-network-connections all:443 lambda-deploy
```

The build command is told to use `docker`, which means the compile happens inside a container that matches the target platform, and the `--allow-network-connections` flag is required because the build needs to reach the network to pull or update images. The deploy command widens that permission to `all:443`, since the deployment step talks to AWS over HTTPS.

This is worth pausing on, because the permission is broader for deployment than for build. `docker` is a narrow allowance, `all:443` is not. It is the plugin asking for outbound HTTPS to reach AWS, and if your environment has a policy on that, this is the command that will need an exception rather than the build.

The README also documents deploying by other routes: the plugin, the AWS Console, SAM and CDK, and there is a `CDK` example in the tree, so infrastructure as code is a supported path rather than a workaround.

Once the function is deployed, invoking it from the CLI uses the standard AWS tooling:

```bash
aws lambda invoke \
  --function-name MyLambda \
  --payload $(echo '{"name":"World","age":30}' | base64) \
  /dev/stdout
```

The payload is base64 encoded, which is the AWS CLI's convention rather than anything specific to this runtime.

## Incubated, experimental, and explicitly not for production

The status section is short and it is the most important paragraph in the README. The Swift runtime client is incubating as part of the Swift Server Workgroup incubation process, and it is described as an experimental package, subject to change, and intended only for evaluation purposes.

That sentence should govern your adoption decision more than any feature list. The package is hosted by awslabs, and it carries the standard set of files a serious project would have, `SECURITY.md`, `CONTRIBUTING.md`, `NOTICE.txt`, `LICENSE.txt` and a `CODE_OF_CONDUCT`-style contribution path, but the incubation status means the API surface can change between minor versions without a deprecation period. The 3.0.0 release on 2026-09-15, followed by 3.0.1 the same day and 3.0.2 a week later on 2026-09-22, is consistent with a project still settling its API. The last push was on 2026-09-22, and the repository is not archived.

Support for a specific problem goes through GitHub issues on the repository, which is a public tracker rather than a support contract.

The licence is Apache-2.0, with a `NOTICE.txt` alongside the licence text. That is permissive, includes an explicit patent grant, and requires the notice file to travel with redistributions. No legal question arises for a team running this in its own account. The permission question that does arise is the product question above: the code is licensed permissively, and the project states that it is not ready to be relied on in production.

The upgrade cost, then, is not in the API surface. It is in the possibility that a version you wrote against in September is not the version you are forced onto in March.

## Where the runtime is the wrong tool

There are three situations where this package is a poor fit, and none of them are about Swift.

The first is a production function that needs a support contract. If a business process depends on a function running, the status line above disqualifies this package on its own terms, and the gap is not filled by the fact that the runtime is hosted in the awslabs organisation.

The second is a function whose language Lambda already runs natively. Building and deploying a custom runtime means you own the artefact, the base image, the platform update path and the behaviour of the runtime client across platform changes. If the language you want is already a managed runtime, that work buys you nothing except a Swift type system on the server side, and a managed runtime gives you the platform's own event source integrations and scaling behaviour without any of it.

The third is a function with a hard latency or memory profile that you cannot yet measure. The layered API goes from closures to performance-sensitive handlers, and the examples cover streaming, background tasks and service lifecycle, but the README does not publish latency or memory numbers for any of these paths, and the repository does not contain a benchmark. On a path where cold start and stream duration decide the architecture, the honest position is that you have to measure on your own account.

The alternative approach, for teams that need Swift on Lambda but want to own less, is to keep the handler in Swift and put it behind the platform's own HTTP surface instead of the Runtime API. The difference in approach is concrete: the Runtime API path gives you the platform's event source integration, the retry and invocation semantics, and the managed scaling, at the cost of owning a container-based artefact; the HTTP path gives you an ordinary service, at the cost of giving up native event sources and the per invocation model.

## Conclusion

Use this package if your team already writes Swift and wants Lambda handlers without hand-rolling a polling client, and if you can live inside its constraints: the Swift 6.x toolchain, a Docker or Apple container build for Amazon Linux, macOS 15 or later for local development, and an API that is explicitly marked experimental and intended only for evaluation. It is the wrong choice for a production service that needs a supported runtime contract, and it is unnecessary if you are writing your function in a language Lambda already runs natively. Verify three things before you commit: that the `lambda-build` container path works on your machine, that the Swift toolchain version your project uses matches the 6.x requirement, and that the version of the package you pin still exposes the handler API your code depends on, since the 3.0.0 release landed on 2026-09-15 and the package is subject to change.

## FAQ

### What is the awslabs swift-aws-lambda-runtime package?

It is a Swift implementation of the AWS Lambda Runtime API, using an embedded asynchronous HTTP client based on SwiftNIO. The README describes it as providing a layered API for Lambda functions, from simple closures to complex, performance-sensitive event handlers.

### How do I create a new Swift Lambda function with this package?

Create an executable package, add the dependency with `swift package add-dependency https://github.com/awslabs/swift-aws-lambda-runtime.git --from 3.0.0`, add the target dependency, then run `swift package lambda-init --allow-writing-to-package-directory` to generate `Sources/MyLambda/MyLambda.swift`.

### How do I test a Swift Lambda function locally?

Run `swift run`, which starts a local server on port 7000, then post JSON to `http://127.0.0.1:7000/invoke` with a `Content-Type: application/json` header. The repository also ships a `Testing` example in the Examples directory.

### How is the function built for Amazon Linux and deployed?

The SPM plugins do it. `swift package --allow-network-connections docker lambda-build` builds inside a container, and `swift package --allow-network-connections all:443 lambda-deploy` deploys it. The README also documents deploying through the AWS Console, SAM and CDK.

### Is swift-aws-lambda-runtime production ready?

No. The README states it is incubating as part of the Swift Server Workgroup incubation process, that it is an experimental package subject to change, and that it is intended only for evaluation purposes.

### What licence does swift-aws-lambda-runtime use?

The package is licensed under Apache-2.0, and the repository carries both LICENSE.txt and NOTICE.txt. The published versions include 3.0.0 and 3.0.1 on 2026-09-15 and 3.0.2 on 2026-09-22.

## Sources

- [awslabs/swift-aws-lambda-runtime on GitHub](https://github.com/awslabs/swift-aws-lambda-runtime)
- [License: Apache-2.0](https://github.com/awslabs/swift-aws-lambda-runtime/blob/main/LICENSE)
- [Project website](https://swiftpackageindex.com/awslabs/swift-aws-lambda-runtime)
- [README](https://github.com/awslabs/swift-aws-lambda-runtime/blob/main/README.md)
- [Releases](https://github.com/awslabs/swift-aws-lambda-runtime/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/awslabs-swift-aws-lambda-runtime
