# soto: a Swift SDK for AWS generated from Amazon's own API models

> Soto is a community supported Swift SDK for AWS whose service APIs are generated from the JSON models Amazon publishes, split into soto-core, generated service files, and a code generator. The judgment is that the generated layer removes the usual hand written SDK drift, while the price is a very large package and a Swift-only audience that has to accept an unofficial SDK.

**soto-project/soto** — Swift SDK for AWS that works on Linux, macOS and iOS

- Repository: https://github.com/soto-project/soto
- Website: https://soto.codes
- Stars: 995 · Forks: 94
- Language: Swift
- License: Apache-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/soto-project-soto

## A Swift SDK whose surface mirrors the AWS REST APIs

Soto is described as a Swift language SDK for Amazon Web Services that works on Linux, macOS and iOS, and it provides access to all AWS services. The sentence that decides how you use it is the next one: the service APIs are a direct mapping of the REST APIs Amazon publishes for each of its services. That is a deliberate design choice with consequences in both directions, and the README makes a point of it later by saying you can use the official AWS documentation for more detail on any command, because the correspondence is one to one.

Who it is for is specific. Server side Swift developers on Linux, macOS users who want the same AWS client on a Mac, and iOS developers who need AWS calls from an app. The topic list names swift-nio, which tells you the concurrency and networking story is built on NIO, and server-side-swift, which tells you the target audience. The project also carries a Swift Server Work Group graduation badge, meaning it passed the incubation process the Swift project runs for libraries that want to be treated as stable dependencies.

It is also explicit about what it is not. Soto is a community supported project and is in no way affiliated with AWS. For a library that talks to a hyperscale provider's API from a language that provider does not officially support, that sentence is the most important line in the README.

## soto-core, generated service files, and the code generator

The library is described as consisting of three parts, and the split explains most of its behaviour.

The first is soto-core, a separate repository, which does all the core request encoding and signing, response decoding and error handling. Every service call passes through it, so it is the part that carries the security weight and the part that would need auditing if you are doing a serious review.

The second is the service api files, which live in the Sources/Soto/Services directory of this repository and define the individual AWS services and their commands with their input and output structures. These are not hand written. They are produced by the third part, the CodeGenerator, which builds the service api files from the JSON model files supplied by Amazon in the models/apis directory.

That pipeline is the core design idea of the project, and it is a good one. A hand written SDK rots, because every time Amazon adds a field to an API, the SDK lags until someone updates it. Soto regenerates the service layer from the source of truth, so the surface tracks Amazon's own models. The cost of that approach is visible in the code shape. Commands are generated, so they tend to expose every parameter Amazon defines rather than the ergonomic subset a human designer would pick, and the input and output structures are wide, which is why a hand written wrapper layer often sits on top.

## Adding Soto to a Package.swift file

Soto uses the Swift Package Manager for dependency management, and the README recommends doing the same in your own codebase. The dependency declaration is a single package entry:

```swift
    dependencies: [
        .package(url: "https://github.com/soto-project/soto.git", from: "7.0.0")
    ],
```

Then you add the target dependencies for each Soto target you want, and the products are per service, so you pull in only what you use:

```swift
    targets: [
        .target(name: "MyApp", dependencies: [
            .product(name: "SotoS3", package: "soto"),
            .product(name: "SotoSES", package: "soto"),
            .product(name: "SotoIAM", package: "soto")
        ]),
    ]
)
```

The from clause starts at 7.0.0, so Swift Package Manager will resolve the newest 7.x release rather than a fixed version, which is convenient until a minor release changes a signature. The alternative, if you are on Xcode 11 or later, is to add the dependency through the Swift Package Manager integration in the IDE instead of editing the manifest by hand.

Note what the manifest change does not do. It does not download the whole service set if you name only the products you need, and it does not require any configuration file, because credentials come from the environment or from the platform.

## Five credential sources, and the one that only belongs in examples

Before any call, the SDK needs AWS credentials, because it signs every request. The README lists five ways to provide them, and the order in that list is a reasonable guide to which one to use.

Environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY come first, and they are the simplest to reason about in local development. ECS container IAM policy and EC2 IAM instance profile are next, and these are the ones that matter in production, because they hand the role to the platform rather than to your code. A shared credentials file in your home directory is the fourth option, and static credentials provided at runtime is the last.

Static credentials at runtime are what the README example uses, and the example is honest about why that is a problem in real code:

```swift
    credentialProvider: .static(accessKeyId: "Your-Access-Key", secretAccessKey: "Your-Secret-Key"),
```

That is a key written into source. It belongs in a test fixture, not in an application. The reason Soto separates the credential provider from the client is precisely so that the same client code can run on a laptop with an environment variable and on an instance with an instance profile, and a team that adopts the example without switching the provider ends up with credentials in their repository.

The full set of providers is documented separately in the credential providers user guide, and the credential resolution order in the SDK is worth reading there before you assume a particular source wins.

## An AWSClient plus a service object, and the async calls that follow

Using Soto means creating an AWSClient and a service object for the service you want to work with. The AWSClient handles all communication with AWS, and the service object carries the configuration and the API for one service. The example in the README puts the two together, and the shape is the same for every service:

```swift
import SotoS3 //ensure this module is specified as a dependency in your package.swift

let bucket = "my-bucket"

let client = AWSClient(
    credentialProvider: .static(accessKeyId: "Your-Access-Key", secretAccessKey: "Your-Secret-Key"),
    httpClientProvider: .createNew
)
let s3 = S3(client: client, region: .uswest2)
```

The region is a parameter of the service object, not of the client, which is what lets one client serve several services in several regions. The calls themselves are async and throwing, so concurrency is part of the signature rather than an option:

```swift
func createBucketPutGetObject() async throws -> S3.GetObjectOutput {
    // Create Bucket, Put an Object, Get the Object
    _ = try await s3.createBucket(bucket: bucket)
    // Upload text file to the s3
    let bodyData = "hello world"
    _ = try await s3.putObject(
        acl: .publicRead,
        body: .string(bodyData),
        bucket: bucket,
        key: "hello.txt"
    )
```

and the read side returns a typed output that you unwrap rather than parse:

```swift
    // download text file just uploaded to S3
    let response = try await s3.getObject(bucket: bucket, key: "hello.txt")
    // print contents of response
    if let body = response.body?.asString() {
        print(body)
    }
    return response
```

The body is a payload wrapper with conversion methods, so you pick the representation you want, and errors surface as Swift errors that you handle with do and catch.

## The package is very large, and the build plugin is the answer

The README states the problem bluntly: Soto is a very large package, and if you would rather not include it in your package dependencies you can instead use the SotoCodeGenerator Swift Package Manager build plugin to generate the Swift source code for only the services and operations you actually need. The plugin lives in its own repository, soto-codegenerator, and it is the escape hatch for anyone whose build time or dependency graph suffers from the full service set.

The size is not an accident. It is the direct consequence of generating every AWS service, including the long tail of services nobody in a given company will ever call. A generated SDK that covers everything is convenient in a different way from one that covers what you need, and Soto offers both, which is the right answer.

Two further limits are worth noting for specific use cases. The service objects are generated from Amazon's models, so a parameter that Amazon has not modelled will not appear, and the shapes follow the wire format rather than Swift conventions, which is why the DynamoDB and Codable guide and the S3 multipart upload guide exist as separate documents. For streaming workloads there is a dedicated streaming payloads guide, and there are specific guides for running Soto on AWS Lambda and with Vapor 4, both of which are server side Swift deployments where the HTTP client and runtime configuration differ from a plain executable.

## Apache-2.0, a NOTICE file, and a community owned SDK

Soto is released under the Apache License, Version 2.0, and the LICENSE file is in the repository root alongside a NOTICE.txt file. That pairing is what you would expect from a project that redistributes code generated from models published by another company, and it is worth reading both files if you ship Soto in a product, since the NOTICE file is where attribution obligations for third party material are recorded. No legal advice is implied by that, and the point here is narrower: the licence is permissive, and the obligations that come with it are the standard ones plus whatever the NOTICE file lists.

On maintenance, the picture is healthy but busy. The recent releases are v7.15.0 on 2026-07-30, v7.16.0 on 2026-09-29, and v7.17.0 on 2026-10-01, so three minor releases in a quarter, and the last push to the repository was on 2026-10-19. The README badges show a Swift 6.1 to 6.3 range, and the repository root carries a .swift-format file, a devcontainer configuration, IntegrationTests, docker/ and scripts/ directories, a SECURITY.md file, CONTRIBUTORS.txt, and an .aws-model-hash file that records which upstream model set the generated code was built from.

That last file is the quiet answer to the drift question. When Amazon updates its models, the hash changes, the generator runs, and the service layer changes with it. The cost of that model is the API surface churn, so a project on Soto should expect to read release notes before each minor bump rather than let the resolver move it.

## Conclusion

Adopt soto if you are writing Swift on Linux, macOS or iOS and need to call AWS services without maintaining a hand written client, and if you can live with a large dependency by using the SotoCodeGenerator build plugin to generate only the services you need. Do not adopt it if you need a vendor supported SDK with a service level agreement, since the project states it is community supported and in no way affiliated with AWS. Before you start, pin the package version you depend on, decide which credential provider fits your runtime rather than hard coding static keys, and read the soto-core documentation, because the request signing and error handling all live there.

## FAQ

### Is soto an official AWS SDK for Swift?

No. The README states that Soto is a community supported project and is in no way affiliated with AWS. It is licensed under the Apache License, Version 2.0 and hosted under the soto-project organisation.

### How do I add soto to a Swift project?

Add it in Package.swift with .package(url: "https://github.com/soto-project/soto.git", from: "7.0.0"), then list the per service products you need, for example SotoS3, SotoSES or SotoIAM, in the target dependencies. On Xcode 11 or later the dependency can be added through the Swift Package Manager integration instead.

### What are the ways soto can find AWS credentials?

The README lists environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, ECS container IAM policy, EC2 IAM instance profile, a shared credentials file in your home directory, and static credentials provided at runtime. The static option is what the example code uses and is the one to avoid in application code.

## Sources

- [License: Apache-2.0](https://github.com/soto-project/soto/blob/main/LICENSE)
- [Project website](https://soto.codes)
- [README](https://github.com/soto-project/soto/blob/main/README.md)
- [Releases](https://github.com/soto-project/soto/releases)
- [soto-project/soto on GitHub](https://github.com/soto-project/soto)

---

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