Migrate aws-sdk-go to aws-sdk-go-v2

Proprietary

Migrate github.com/aws/aws-sdk-go, whose support AWS ended in July 2025, to github.com/aws/aws-sdk-go-v2. The go directive rises to the Go 1.24 the v2 modules require; the session becomes a config loaded through a context, with each aws.Config field it carried — the region, the endpoint, the retry count, a static or shared credentials provider — becoming the loader option that replaces it; each client is built with NewFromConfig, a per-client region override — or a config local that is nil or sets only the region — becoming a functional option; and every operation takes a context. A config built field by field instead of in one literal keeps its shape: the load moves to the local's declaration and the writes that follow retarget onto v2's own config, with the S3 addressing style — which v2 holds on the client's options rather than the config — hoisted into a local the constructor reads. Shapes and enums follow the manifest to the types sub-package, an enum field losing the aws.String its *string needed and an enum list changing element type with it; v1's fluent setters become assignments; and a field v2 holds by value loses the dereference that read it, or regains the pointer where it was passed on — v1 could report such a field as nil and v2 cannot, so review a nil test downstream of one. The packages v2 relocated follow too: s3manager becomes feature/s3/manager, ec2metadata becomes feature/ec2/imds, the DynamoDB expression builder becomes feature/dynamodb/expression — short of an operand v2's encoder would store differently — rdsutils.BuildAuthToken becomes feature/rds/auth's, taking a context and the config's credentials provider, and stscreds moves up beside credentials, each bound back to the name the file already spells, and the per-service iface packages v2 deleted are regenerated into the module under internal/awsiface, so the interfaces mocks embed still exist; a mockery mock of one is regenerated against v2's signatures, the expectations set on it gaining the context v2 passes first, and a hand-written stub overriding a page iterator gains the operation v2's paginator calls instead, serving the pages its override hands out in turn. dynamodbattribute is ported onto v2's AttributeValue and generated under internal/awscompat, since v2's attributevalue ignores json tags and stores an empty value as itself where v1 stored NULL, so items written before the migration still read back. A shape's Validate becomes a generated function checking v1's rules and reporting them in v1's words. Where the go directive rises past 1.24, a printf-style call whose format is not a constant gains a "%s" format, which that release's vet otherwise rejects. Where v2 restructured rather than renamed, a wrapper keeps the v1 call site's shape: a page iterator's callback is driven by the v2 paginator in a function literal called on the spot, a waiter becomes v2's waiter type bounded by a generated constant, an inline session.New becomes a generated loader that panics as session.Must did, as does a session.Must anywhere but an x := statement, which expands into the load and its panic, a handler a function adds to its session's Send or UnmarshalError list becomes a generated stand-in for that list on the config's APIOptions, run per attempt around the round trip in v1's order and handed the service and operation names, the attempt's start and the input — so metrics and logs it feeds keep their meaning, though the operation and input print differently — EC2Metadata.Region and Available go through generated helpers, a DynamoDB AttributeValue setting one scalar member becomes that member's v2 type and a read of one goes through a generated getter answering nil where v1's field was unset, awserr.New with nothing wrapped becomes a generated error reading as v1's did, aws.WriteAtBuffer moves to the transfer manager, an endpoint gains the https scheme v1 added to one written without, and a list or map v2 holds by value is converted at the API boundary by generated helpers so the code around it keeps its v1 shape. v1 took no context anywhere v2 takes one, so a function with none in scope gets context.TODO() — review those and plumb a real context through. A package migrates whole or not at all, since a half-migrated one does not compile, but the module does not: a file holding a construct with no faithful v2 form — the rest of the v1 request plumbing, such as a handler reading the request's error or response, a session compared to nil, a shared-credentials provider assigned to a config field, a v1-only helper the manifest cannot account for, a shape v2 turned into a union interface such as DynamoDB's AttributeValue, a sub-package v2 moved or dropped such as s3crypto, a type implementing dynamodbattribute's Marshaler, which takes v1's AttributeValue, a stub overriding a WithContext, Request or waiter method v2's client would never call — is left as it is along with the rest of its package, each listed in the blockers data table, and the rest of the module moves around it. Both requires then sit in the go.mod side by side. A client and a shape cross package boundaries, so callers of what stayed behind will not compile until it is migrated by hand; that table is the list to work through, and FindAwsSdkGoV1Usage marks the constructs within each file. go.mod requires each v2 module the migrated source imports, along with the indirect requirements they bring, at versions the regenerated iface packages compile against — a module the build already selects higher keeps its version — and go.sum gains their hashes, so the result builds under -mod=readonly as it stands. Then run go mod tidy: the build does not need it, but it drops what the migration leaves behind — the requirements only v1 needed, the go.sum lines nothing reads any more, and an // indirect marker on a module the source now imports directly.

org.openrewrite.golang.migration.MigrateAwsSdkGoToV2
mod run . --recipe=org.openrewrite.golang.migration.MigrateAwsSdkGoToV2

Install it once, then run it on every repository under the current directory. New to the Moderne CLI? Set it up.