Back to DevOps & CI/CD

aws-sdk-java-v2-core

AWS SDKJavaCloudClient ConfigurationAuthenticationHTTP ClientPerformanceBest Practices
282📄 MIT🕒 2026-06-15Source ↗

Install this skill

npx skills add giuseppe-trisciuoglio/developer-kit

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

The aws-sdk-java-v2-core skill provides a standardized approach for integrating Amazon Web Services into Java applications using the official Version 2 SDK. It focuses on modular service client architecture, which allows developers to isolate HTTP client dependencies and minimize binary footprints. This skill encompasses the programmatic construction of service clients, granular management of credential provider chains, and the enforcement of explicit timeout policies for network-bound operations. By utilizing the builder pattern and immutable client configurations, this skill ensures that AWS service interactions remain thread-safe and performant. It emphasizes resource lifecycle management, specifically the requirement to close clients to prevent connection leaks, and provides patterns for integrating custom metric publishers and proxy configurations into the communication layer of Java-based cloud services.

When to Use This Skill

  • Building microservices that read from and write to Amazon S3
  • Developing background workers that process SQS message queues
  • Implementing custom authentication for IAM-protected internal services
  • Configuring cross-account access using temporary security credentials

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • Configure an S3 client in Java with a custom timeout
  • How to use default credentials for AWS SDK v2 in Java
  • Setting up an ApacheHttpClient for AWS SDK v2
  • Implement programmatic IAM authentication in my Java application
  • Java SDK v2 client lifecycle best practices

Pro Tips

  • 💡Always utilize the try-with-resources statement or explicitly close your AWS service clients to prevent resource leaks, especially in high-throughput applications.
  • 💡Prioritize using AWS IAM roles over hardcoded credentials for enhanced security, especially in EC2, ECS, or Lambda environments.
  • 💡Implement comprehensive retry and error handling strategies, leveraging the SDK's built-in capabilities, to build more resilient applications against transient network issues and service limits.

What this skill does

  • Modular client construction using the Builder pattern
  • Automated credential resolution via the DefaultCredentialsProvider chain
  • Granular control over API call, connection, and attempt timeouts
  • Support for pluggable HTTP client implementations like Apache or Netty
  • Integration with CloudWatch metrics for real-time telemetry

When not to use it

  • When building simple scripts that can rely on the AWS CLI instead of Java
  • In environments where low-overhead, language-agnostic integrations are required
  • When performance constraints strictly forbid the overhead of a JVM-based SDK

Example workflow

  1. Instantiate a specific service client using the class builder
  2. Define an override configuration for connection and request timeouts
  3. Specify a credentials provider appropriate for the runtime environment
  4. Inject the configured client into the application service layer
  5. Wrap service calls in a try-with-resources block for automatic cleanup

Prerequisites

  • JDK 8 or higher
  • Maven or Gradle project dependencies for specific AWS service modules
  • Configured AWS credentials in environment variables or profile files

Pitfalls & limitations

  • !Failure to close service clients leads to connection pool exhaustion
  • !Hardcoding credentials instead of using the provider chain risks security breaches
  • !Over-configuring timeouts can cause silent, long-running hangs in network calls

FAQ

Why should I use the v2 SDK instead of v1?
The v2 SDK is modular, which reduces the application package size, and includes non-blocking I/O support via Netty, offering better performance.
Do I need to manage credentials manually?
No, the DefaultCredentialsProvider chain automatically searches environment variables, system properties, and profiles, which is the recommended practice.
Is it safe to share a client instance across threads?
Yes, AWS SDK v2 service clients are thread-safe and designed to be shared, though you must be careful to manage their lifecycle correctly.

How it compares

Using this skill enforces industry-standard configuration patterns instead of manually implementing HTTP request signing or basic boilerplate, ensuring consistency and type safety.

Source & trust

282 stars📄 MIT🕒 Updated 2026-06-15
📄 Full skill instructions — original source: giuseppe-trisciuoglio/developer-kit
# AWS SDK for Java 2.x - Core Patterns

## Overview

Configure AWS service clients, authentication, timeouts, HTTP clients, and implement best practices for AWS SDK for Java 2.x applications. This skill provides essential patterns for building robust, performant, and secure integrations with AWS services.

## When to Use

Use this skill when:
- Setting up AWS SDK for Java 2.x service clients with proper configuration
- Configuring authentication and credential management strategies
- Implementing client lifecycle management and resource cleanup
- Optimizing performance with HTTP client configuration and connection pooling
- Setting up proper timeout configurations for API calls
- Implementing error handling and retry policies
- Enabling monitoring and metrics collection
- Integrating AWS SDK with Spring Boot applications
- Testing AWS integrations with LocalStack and Testcontainers

## Quick Start

### Basic Service Client Setup

import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

// Basic client with region
S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.build();

// Always close clients when done
try (S3Client s3 = S3Client.builder().region(Region.US_EAST_1).build()) {
// Use client
} // Auto-closed


### Basic Authentication

// Uses default credential provider chain
S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.build(); // Automatically detects credentials


## Client Configuration

### Service Client Builder Pattern

import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.apache.ProxyConfiguration;
import software.amazon.awssdk.metrics.publishers.cloudwatch.CloudWatchMetricPublisher;
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import java.time.Duration;
import java.net.URI;

// Advanced client configuration
S3Client s3Client = S3Client.builder()
.region(Region.EU_SOUTH_2)
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
.overrideConfiguration(b -> b
.apiCallTimeout(Duration.ofSeconds(30))
.apiCallAttemptTimeout(Duration.ofSeconds(10))
.addMetricPublisher(CloudWatchMetricPublisher.create()))
.httpClientBuilder(ApacheHttpClient.builder()
.maxConnections(100)
.connectionTimeout(Duration.ofSeconds(5))
.proxyConfiguration(ProxyConfiguration.builder()
.endpoint(URI.create("http://proxy:8080"))
.build()))
.build();


### Separate Configuration Objects

ClientOverrideConfiguration clientConfig = ClientOverrideConfiguration.builder()
.apiCallTimeout(Duration.ofSeconds(30))
.apiCallAttemptTimeout(Duration.ofSeconds(10))
.addMetricPublisher(CloudWatchMetricPublisher.create())
.build();

ApacheHttpClient httpClient = ApacheHttpClient.builder()
.maxConnections(100)
.connectionTimeout(Duration.ofSeconds(5))
.build();

S3Client s3Client = S3Client.builder()
.region(Region.EU_SOUTH_2)
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
.overrideConfiguration(clientConfig)
.httpClient(httpClient)
.build();


## Authentication and Credentials

### Default Credentials Provider Chain

// SDK automatically uses default credential provider chain:
// 1. Java system properties (aws.accessKeyId and aws.secretAccessKey)
// 2. Environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY)
// 3. Web identity token from AWS_WEB_IDENTITY_TOKEN_FILE
// 4. Shared credentials and config files (~/.aws/credentials and ~/.aws/config)
// 5. Amazon ECS container credentials
// 6. Amazon EC2 instance profile credentials

S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.build(); // Uses default credential provider chain


### Explicit Credentials Providers

import software.amazon.awssdk.auth.credentials.*;

// Environment variables
CredentialsProvider envCredentials = EnvironmentVariableCredentialsProvider.create();

// Profile from ~/.aws/credentials
CredentialsProvider profileCredentials = ProfileCredentialsProvider.create("myprofile");

// Static credentials (NOT recommended for production)
CredentialsProvider staticCredentials = StaticCredentialsProvider.create(
AwsBasicCredentials.create("accessKeyId", "secretAccessKey")
);

// Instance profile (for EC2)
CredentialsProvider instanceProfileCredentials = InstanceProfileCredentialsProvider.create();

// Use with client
S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.credentialsProvider(profileCredentials)
.build();


### SSO Authentication Setup

# ~/.aws/config
[default]
sso_session = my-sso
sso_account_id = 111122223333
sso_role_name = SampleRole
region = us-east-1
output = json

[sso-session my-sso]
sso_region = us-east-1
sso_start_url = https://provided-domain.awsapps.com/start
sso_registration_scopes = sso:account:access


# Login before running application
aws sso login

# Verify active session
aws sts get-caller-identity


## HTTP Client Configuration

### Apache HTTP Client (Recommended for Sync)

import software.amazon.awssdk.http.apache.ApacheHttpClient;

ApacheHttpClient httpClient = ApacheHttpClient.builder()
.maxConnections(100)
.connectionTimeout(Duration.ofSeconds(5))
.socketTimeout(Duration.ofSeconds(30))
.connectionTimeToLive(Duration.ofMinutes(5))
.expectContinueEnabled(true)
.build();

S3Client s3Client = S3Client.builder()
.httpClient(httpClient)
.build();


### Netty HTTP Client (For Async Operations)

import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.http.nio.netty.SslProvider;

NettyNioAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
.maxConcurrency(100)
.connectionTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(30))
.writeTimeout(Duration.ofSeconds(30))
.sslProvider(SslProvider.OPENSSL) // Better performance than JDK
.build();

S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
.httpClient(httpClient)
.build();


### URL Connection HTTP Client (Lightweight)

import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;

UrlConnectionHttpClient httpClient = UrlConnectionHttpClient.builder()
.socketTimeout(Duration.ofSeconds(30))
.build();


## Best Practices

### 1. Reuse Service Clients

**DO:**
@Service
public class S3Service {
private final S3Client s3Client;

public S3Service() {
this.s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.build();
}

// Reuse s3Client for all operations
}


**DON'T:**
public void uploadFile(String bucket, String key) {
// Creates new client each time - wastes resources!
S3Client s3 = S3Client.builder().build();
s3.putObject(...);
s3.close();
}


### 2. Configure API Timeouts

S3Client s3Client = S3Client.builder()
.overrideConfiguration(b -> b
.apiCallTimeout(Duration.ofSeconds(30))
.apiCallAttemptTimeout(Duration.ofMillis(5000)))
.build();


### 3. Close Unused Clients

// Try-with-resources
try (S3Client s3 = S3Client.builder().build()) {
s3.listBuckets();
}

// Explicit close
S3Client s3Client = S3Client.builder().build();
try {
s3Client.listBuckets();
} finally {
s3Client.close();
}


### 4. Close Streaming Responses

try (ResponseInputStream<GetObjectResponse> s3Object =
s3Client.getObject(GetObjectRequest.builder()
.bucket(bucket)
.key(key)
.build())) {

// Read and process stream immediately
byte[] data = s3Object.readAllBytes();

} // Stream auto-closed, connection returned to pool


### 5. Optimize SSL for Async Clients

**Add dependency:**
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.61.Final</version>
<scope>runtime</scope>
</dependency>


**Configure SSL:**
NettyNioAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
.sslProvider(SslProvider.OPENSSL)
.build();

S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
.httpClient(httpClient)
.build();


## Spring Boot Integration

### Configuration Properties

@ConfigurationProperties(prefix = "aws")
public record AwsProperties(
String region,
String accessKeyId,
String secretAccessKey,
S3Properties s3,
DynamoDbProperties dynamoDb
) {
public record S3Properties(
Integer maxConnections,
Integer connectionTimeoutSeconds,
Integer apiCallTimeoutSeconds
) {}

public record DynamoDbProperties(
Integer maxConnections,
Integer readTimeoutSeconds
) {}
}


### Client Configuration Beans

@Configuration
@EnableConfigurationProperties(AwsProperties.class)
public class AwsClientConfiguration {

private final AwsProperties awsProperties;

public AwsClientConfiguration(AwsProperties awsProperties) {
this.awsProperties = awsProperties;
}

@Bean
public S3Client s3Client() {
return S3Client.builder()
.region(Region.of(awsProperties.region()))
.credentialsProvider(credentialsProvider())
.overrideConfiguration(clientOverrideConfiguration(
awsProperties.s3().apiCallTimeoutSeconds()))
.httpClient(apacheHttpClient(
awsProperties.s3().maxConnections(),
awsProperties.s3().connectionTimeoutSeconds()))
.build();
}

private CredentialsProvider credentialsProvider() {
if (awsProperties.accessKeyId() != null &&
awsProperties.secretAccessKey() != null) {
return StaticCredentialsProvider.create(
AwsBasicCredentials.create(
awsProperties.accessKeyId(),
awsProperties.secretAccessKey()));
}
return DefaultCredentialsProvider.create();
}

private ClientOverrideConfiguration clientOverrideConfiguration(
Integer apiCallTimeoutSeconds) {
return ClientOverrideConfiguration.builder()
.apiCallTimeout(Duration.ofSeconds(
apiCallTimeoutSeconds != null ? apiCallTimeoutSeconds : 30))
.apiCallAttemptTimeout(Duration.ofSeconds(10))
.build();
}

private ApacheHttpClient apacheHttpClient(
Integer maxConnections,
Integer connectionTimeoutSeconds) {
return ApacheHttpClient.builder()
.maxConnections(maxConnections != null ? maxConnections : 50)
.connectionTimeout(Duration.ofSeconds(
connectionTimeoutSeconds != null ? connectionTimeoutSeconds : 5))
.socketTimeout(Duration.ofSeconds(30))
.build();
}
}


### Application Properties

aws:
region: us-east-1
s3:
max-connections: 100
connection-timeout-seconds: 5
api-call-timeout-seconds: 30
dynamo-db:
max-connections: 50
read-timeout-seconds: 30


## Error Handling

import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.core.exception.SdkServiceException;

try {
s3Client.getObject(request);

} catch (S3Exception e) {
// Service-specific exception
System.err.println("S3 Error: " + e.awsErrorDetails().errorMessage());
System.err.println("Error Code: " + e.awsErrorDetails().errorCode());
System.err.println("Status Code: " + e.statusCode());
System.err.println("Request ID: " + e.requestId());

} catch (SdkServiceException e) {
// Generic service exception
System.err.println("AWS Service Error: " + e.getMessage());

} catch (SdkClientException e) {
// Client-side error (network, timeout, etc.)
System.err.println("Client Error: " + e.getMessage());
}


## Testing Patterns

### LocalStack Integration

@TestConfiguration
public class LocalStackAwsConfig {

@Bean
public S3Client s3Client() {
return S3Client.builder()
.region(Region.US_EAST_1)
.endpointOverride(URI.create("http://localhost:4566"))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create("test", "test")))
.build();
}
}


### Testcontainers with LocalStack

@Testcontainers
@SpringBootTest
class S3IntegrationTest {

@Container
static LocalStackContainer localstack = new LocalStackContainer(
DockerImageName.parse("localstack/localstack:3.0"))
.withServices(LocalStackContainer.Service.S3);

@DynamicPropertySource
static void overrideProperties(DynamicPropertyRegistry registry) {
registry.add("aws.s3.endpoint",
() -> localstack.getEndpointOverride(LocalStackContainer.Service.S3));
registry.add("aws.region", () -> localstack.getRegion());
registry.add("aws.access-key-id", localstack::getAccessKey);
registry.add("aws.secret-access-key", localstack::getSecretKey);
}
}


## Maven Dependencies

<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.25.0</version> // Use latest stable version
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- Core SDK -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sdk-core</artifactId>
</dependency>

<!-- Apache HTTP Client (recommended for sync) -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
</dependency>

<!-- Netty HTTP Client (for async) -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>

<!-- URL Connection HTTP Client (lightweight) -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>

<!-- CloudWatch Metrics -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>cloudwatch-metric-publisher</artifactId>
</dependency>

<!-- OpenSSL for better performance -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.61.Final</version>
<scope>runtime</scope>
</dependency>
</dependencies>


## Gradle Dependencies

dependencies {
implementation platform('software.amazon.awssdk:bom:2.25.0')

implementation 'software.amazon.awssdk:sdk-core'
implementation 'software.amazon.awssdk:apache-client'
implementation 'software.amazon.awssdk:netty-nio-client'
implementation 'software.amazon.awssdk:cloudwatch-metric-publisher'

runtimeOnly 'io.netty:netty-tcnative-boringssl-static:2.0.61.Final'
}


## Examples

### Basic S3 Upload

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

try (S3Client s3 = S3Client.builder().region(Region.US_EAST_1).build()) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket("my-bucket")
.key("uploads/file.txt")
.build();

s3.putObject(request, RequestBody.fromString("Hello, World!"));
}


### S3 List Objects with Pagination

import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;

try (S3Client s3 = S3Client.builder().region(Region.US_EAST_1).build()) {
ListObjectsV2Request request = ListObjectsV2Request.builder()
.bucket("my-bucket")
.build();

ListObjectsV2Response response = s3.listObjectsV2(request);
response.contents().forEach(object -> {
System.out.println("Object key: " + object.key());
});
}


### Async S3 Upload

import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

S3AsyncClient s3AsyncClient = S3AsyncClient.builder().build();

PutObjectRequest request = PutObjectRequest.builder()
.bucket("my-bucket")
.key("async-upload.txt")
.build();

CompletableFuture<PutObjectResponse> future = s3AsyncClient.putObject(
request, Async.fromString("Hello, Async World!"));

future.thenAccept(response -> {
System.out.println("Upload completed: " + response.eTag());
}).exceptionally(error -> {
System.err.println("Upload failed: " + error.getMessage());
return null;
});


## Performance Considerations

1. **Connection Pooling**: Default max connections is 50. Increase for high-throughput applications.
2. **Timeouts**: Always set both apiCallTimeout and apiCallAttemptTimeout.
3. **Client Reuse**: Create clients once, reuse throughout application lifecycle.
4. **Stream Handling**: Close streams immediately to prevent connection pool exhaustion.
5. **Async for I/O**: Use async clients for I/O-bound operations.
6. **OpenSSL**: Use OpenSSL with Netty for better SSL performance.
7. **Metrics**: Enable CloudWatch metrics to monitor performance.

## Security Best Practices

1. **Never hardcode credentials**: Use credential providers or environment variables.
2. **Use IAM roles**: Prefer IAM roles over access keys when possible.
3. **Rotate credentials**: Implement credential rotation for long-lived keys.
4. **Least privilege**: Grant minimum required permissions.
5. **Enable SSL**: Always use HTTPS endpoints (default).
6. **Audit logging**: Enable AWS CloudTrail for API call auditing.

## Related Skills

- aws-sdk-java-v2-s3 - S3-specific patterns and examples
- aws-sdk-java-v2-dynamodb - DynamoDB patterns and examples
- aws-sdk-java-v2-lambda - Lambda patterns and examples

## References

See [references/](references/) for detailed documentation:

- [Developer Guide](references/developer-guide.md) - Comprehensive guide and architecture overview
- [API Reference](references/api-reference.md) - Complete API documentation for core classes
- [Best Practices](references/best-practices.md) - In-depth best practices and configuration examples

## Additional Resources

- [AWS SDK for Java 2.x Developer Guide](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html)
- [AWS SDK for Java 2.x API Reference](https://sdk.amazonaws.com/java/api/latest/)
- [Best Practices](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/best-practices.html)
- [GitHub Repository](https://github.com/aws/aws-sdk-java-v2)

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/aws-sdk-java-v2-core/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/giuseppe-trisciuoglio/developer-kit/aws-sdk-java-v2-core/SKILL.md
  • Cursor: ~/.cursor/skills/giuseppe-trisciuoglio/developer-kit/aws-sdk-java-v2-core/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/giuseppe-trisciuoglio/developer-kit/aws-sdk-java-v2-core/SKILL.md

🚀 Install with CLI:
npx skills add giuseppe-trisciuoglio/developer-kit

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid devops & ci/cd issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under DevOps & CI/CD and is published by Giuseppe Trisciuoglio, maintained in giuseppe-trisciuoglio/developer-kit.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.