> ## Documentation Index
>
> Fetch the complete documentation index at: https://lithi.ai/llms.txt
>
> Use this file to discover all available pages before exploring further.

---
title: Amazon S3
description: >-
  Read input from and write results to Amazon S3. Pin the exact object version, register a
  credential reference, and prove a small transfer before real work depends on it.
route: /docs/compute/integrations/aws-s3
page_id: docs-compute-integrations-aws-s3
page_type: howTo
content_layer: guided documentation
surface_profile: guided_docs
audience: Administrators connecting Compute to buckets their team already owns
voice: D
reader_question: How do I read input from and deliver results to my own S3 bucket?
primary_action: Register a destination for results
source_locale: en-US
source_status: APPROVED
source_version: docs-compute-integrations-aws-s3-en-us-2026-09-05-v1
last_updated: '2026-09-05'
robots: index
claim_registry_pinned: true
claim_registry_resync: "npm run governed:tsx -- scripts/build-compute-public-claim-registry.ts --write"
---

## What this adapter states

Read these eleven facts off the adapter's own descriptor and its published conformance matrix before you register anything.

| Fact | Where you read it |
| --- | --- |
| Provider product | Amazon S3 object storage |
| Tested upstream version | The matrix names the exact API version tested |
| Supported direction | Input, output, or both, as declared on the descriptor |
| Credential mode | A stored credential reference, never a literal secret |
| Input snapshot binding | A `version_id` and a `content_sha256` pinned before admission |
| Formats | The formats the workflow declares, listed on its descriptor |
| Output commit mode | Written once to a new partition, verified, then committed |
| Unsupported fields | Named explicitly in the matrix, not left out |
| Limits | Measured size, count and rate bounds in the matrix |
| Expiry | The delivery authority's lifetime and who renews it |
| Compatibility level | One of the four named levels, with a matrix version |

If any row is blank or unnamed, treat it as untested. See [what each compatibility level commits to](/docs/compute/integrations/compatibility-levels) before you plan around a gap.

## Before you start

You need an administration credential, a bucket your team owns, and a secret already stored in your credential store.

Decide the prefix before you decide anything else. A prefix is a better grant than a bucket, and a bucket is a better grant than an account.

## Pin exact object identity

Compute never runs against a live prefix. The input is snapshotted first, and the run reads those exact bytes for its whole life.

For a single object, pin the object version. For a set, pin a manifest that lists each object and its version, and let the snapshot cover the manifest.

Check the `version_id` and `content_sha256` on your quote, then again on the result's provenance record. If the pair matches, you know which bytes produced which result.

## Register a credential reference

Your request carries a `credential_ref`. That is a pointer to a stored secret, not the secret itself.

Never put a literal key in a request, a configuration file or a command line. Credentials are stripped before manifest, job and delivery records are persisted.

Grant read on the input prefix and write on a separate output prefix. Do not reuse one grant for both.

## Test with a bounded transfer first

Use the source family's `test` operation on one object, and the destination family's `test` on one small write.

A destination test has to reach a committed state, not just a created object. Many grants can create an object and cannot finalize one, and that gap only appears when real work is delivered.

Keep both tests small on purpose. A test that reads everything proves a wide grant works, which is not the question.

## Watch region and expiry

Region is a constraint, not a preference. Confirm the bucket's region is one your account policy admits, before you register it.

Delivery authority is time-bounded by design. `AUTHORITY_EXPIRED` means the permission lapsed, not that a result was lost, and the fix is to renew and retry the delivery.

Write the expiry and its owner down next to the destination record. Somebody has to renew it, and that person should not be discovering it during an incident.

## Confirm success

The source and destination both read back as `VERIFIED`. Both `test` operations pass, and the destination test reaches a committed write.

A real job's delivery then progresses to `COMMITTED` and finally to `CUSTOMER_ACKNOWLEDGED`. Do not treat `WRITTEN_UNVERIFIED` as done; the bytes exist and nothing has confirmed them.

Keep the receipt reference the apply returned. Quote it to support if access behaves differently later, and never send a key or a signed URL.

[Register a destination for results](/docs/compute/configure/destinations)
