To save a generated PDF to Amazon S3 in Java, first produce the PDF, then upload it as an S3 object. With AWS SDK for Java 2.x, the simplest option when the PDF already exists on disk is S3Client.putObject with a Path. If your generator produces a stream instead, upload it with an accurate content length or an appropriate content-stream provider. The AWS upload examples below do not depend on a particular PDF-generation library.
How the PDF-to-S3 workflow works
PDF creation and S3 storage are separate operations. Your Java PDF library creates a file, byte array, or stream; the AWS SDK sends that output to a bucket under an object key. The bucket must already exist, and the AWS identity used by the application must be allowed to write the object.
The examples here use AWS SDK for Java 2.x unless marked otherwise. Use the PDF library already in your application to create the document; no specific generator is required by the S3 upload code.
- Generate the PDF and retain its output as a local
Path/Fileor an input stream. - Configure AWS credentials and the bucket’s region through your application’s normal AWS SDK setup.
- Choose the destination bucket and object key, such as
reports/2026/invoice-123.pdf. - Upload the file or stream, then treat the operation as successful only after the SDK call completes without an exception.
Upload a PDF file with AWS SDK for Java 2.x
If the PDF has already been saved to disk, pass its Path to the synchronous S3Client.putObject overload. This is the most direct 2.x approach for a file-backed PDF and avoids reading the entire file into application memory first.
import java.nio.file.Path;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
public final class PdfUploader {
public static void uploadPdf(S3Client s3Client, Path pdfPath,
String bucketName, String objectKey) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key(objectKey)
.contentType("application/pdf")
.build();
s3Client.putObject(request, pdfPath);
}
}
contentType("application/pdf") sets object metadata that helps clients recognize the file as a PDF. It is an application choice, not a prerequisite for S3 to store the bytes. Construct the S3Client using the region and credential configuration appropriate to your deployment; the snippet assumes that setup is already complete.
A complete call needs a real bucket name, the path to the generated file, and an object key. The key is the object’s name inside the bucket, not a local path. For example, reports/2026/invoice-123.pdf creates an object with that key; the slash-separated parts are key text, not directories that must first be created.
Choose an object key and overwrite policy
A repeat upload to the same bucket and key targets the same object name. Decide whether that is intended: a stable key can represent the current version of a report, while a unique key can preserve separate generated files. If the bucket uses versioning, its configuration affects how successive writes to a key are retained; decide the key and retention behavior as part of the application’s storage policy.
- Use predictable keys when downstream code needs to find a known report, such as
invoices/2026/123.pdf. - Use unique identifiers or timestamps when each generated PDF should be retained under a distinct name.
- Do not concatenate untrusted input into keys without applying your application’s validation and naming rules.
Upload directly from an InputStream
Some generators can write PDF bytes to an in-memory buffer or expose an InputStream rather than a disk file. For a known, exact byte length, SDK 2.x provides RequestBody.fromInputStream(inputStream, contentLength). The length must describe the actual bytes that will be read from the stream.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteRank #2
import java.io.InputStream;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
public static void uploadPdfStream(S3Client s3Client, InputStream pdfStream,
long contentLength, String bucketName,
String objectKey) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key(objectKey)
.contentType("application/pdf")
.build();
s3Client.putObject(request,
RequestBody.fromInputStream(pdfStream, contentLength));
}
This method consumes the supplied stream. Manage its lifecycle according to how it was created; for a stream opened by your code, use try-with-resources around the upload so it is closed on success or failure.
try (InputStream pdfStream = openGeneratedPdfStream()) {
uploadPdfStream(s3Client, pdfStream, exactPdfByteLength,
bucketName, objectKey);
}
Do not guess contentLength. A value smaller than the real stream can truncate the uploaded object; a larger value can fail the upload or leave the connection waiting for bytes that never arrive. If the generator cannot provide the exact length, use an AWS-documented ContentStreamProvider approach or evaluate an appropriate transfer or multipart strategy for the payload rather than claiming an invented size.
SDK 1.x uses a different upload API
Projects still using AWS SDK for Java 1.x should not paste in the 2.x request/body code. The 1.x file-upload pattern uses an AmazonS3 client and the bucket, key, and file arguments directly.
import com.amazonaws.services.s3.AmazonS3;
import java.io.File;
public static void uploadPdfV1(AmazonS3 s3, String bucketName,
String objectKey, File pdfFile) {
s3.putObject(bucketName, objectKey, pdfFile);
}
Confirm which SDK generation the project actually depends on before selecting an example. The client classes and upload request forms differ between v1 and v2.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →File upload, stream upload, and large PDFs
| Situation | Practical choice | Important consideration |
|---|---|---|
| PDF already exists as a local file | SDK 2.x putObject(request, path) |
Direct path-based upload; avoids loading the whole file into application memory. |
| PDF is available as a stream with known size | SDK 2.x RequestBody.fromInputStream(stream, length) |
The length must exactly match the stream’s bytes. |
| Stream size is unknown | Use an AWS-documented content-stream provider or a suitable transfer strategy | Do not guess a length or buffer a very large PDF without considering memory use. |
| Object is larger than a single-operation upload supports | Use multipart or another documented transfer approach | AWS documents a 5 GB maximum for a single-operation SDK, REST API, or CLI upload. |
AWS documents multipart upload for objects in the 5 MB to 50 TB range. These are S3 product limits, not a guarantee that every SDK call or application configuration is appropriate at every size. For large files, plan for multipart transfer behavior, retries, cleanup of incomplete uploads, and the memory and time characteristics of your generator.
Credentials, region, permissions, and encryption
The SDK client must be configured for the target bucket’s region and obtain credentials through the application’s normal AWS setup. Avoid embedding access keys in source code. The identity needs permission to write to the selected bucket and key; bucket policies or organization-level controls may impose additional conditions.
Apply least privilege: grant only the access the application needs, scoped to the relevant bucket or key prefix when your policy design allows. S3 documentation says new uploads use SSE-S3 by default. SSE-KMS can be configured when required, but the uploader also needs the corresponding permissions to use the KMS key. Follow the security and encryption policy for the particular bucket and data.
Verify success and handle failures
The synchronous putObject call returns only after the request succeeds or throws an exception. Catch and report AWS SDK/service exceptions at the application boundary; do not log a success message before the call completes. Record enough context to diagnose failures—such as the destination bucket/key and request outcome—without logging credentials or sensitive PDF contents.
Rank #4
- Confirm the bucket name, region, and key used by the application.
- Check the object’s metadata and content through the application’s normal verification path when the workflow requires confirmation.
- For stream uploads, investigate a wrong length or a stream that cannot be read again if a retry is attempted.
- For large uploads, select a transfer approach that supports the size and retry requirements of the application.
Troubleshooting common upload problems
Access denied
Check the caller’s identity permissions, bucket policy, and any organization-level restrictions. If SSE-KMS is configured, verify that the identity is allowed to use the selected key as well as write to the bucket.
Bucket or region errors
Verify that the bucket exists and that the client is configured for the bucket’s region. A valid bucket name paired with an incorrectly configured client can still produce a failed request.
Object is truncated
For an InputStream upload, compare the supplied length to the actual PDF byte count. A length smaller than the stream can result in truncation; regenerate or reopen the stream as needed and send the exact length.
Upload fails or appears to hang on a stream
A length larger than the available bytes can cause upload failure or a wait for data that never arrives. Check the stream’s source and ensure the declared length is exact. For unknown-size output, use an appropriate provider or transfer strategy.
Free tools Windows power users keep installed
One-click scans. No signup required.
Best Value
PDF downloads with the wrong type
Set object metadata to application/pdf if your consumers rely on the content type. The bytes can be stored without that metadata, but clients may handle or present the object differently.
Large object rejected
If the PDF exceeds the documented 5 GB single-operation upload limit, use multipart or a suitable transfer approach. The console’s documented maximum single-file upload is 160 GB, which is a separate limit and should not be confused with API/SDK upload limits.
Or skip the browser setup
If the PDF you need to store is a screenshot of a web page, ScreenshotNeo can return a PDF directly from a single request; your application can then save or forward the response bytes to its own storage workflow. It is a screenshot API and MCP server, not a general-purpose PDF generator.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
For PDF output, request the PDF format using the API’s documented parameters. See the ScreenshotNeo API documentation for request options and output formats. ScreenshotNeo removes known cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are not billed. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots.
Recommended Free Tools
ScreenshotNeo is useful when the PDF starts as a web page capture rather than output from an application’s PDF library. Sign up for ScreenshotNeo free to get 1,000 screenshots a month with no card.
Frequently Asked Questions
Does uploading a PDF to S3 create the PDF?
No. Your Java PDF library or application creates the document; the AWS SDK upload stores the resulting file or bytes as an S3 object.
Can I use the same upload code for AWS SDK v1 and v2?
No. SDK v1 uses the AmazonS3 client API, while SDK v2 uses S3Client and request/body types.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

