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

# Amazon S3

> Connect a Job's input source and destination to your S3 bucket

A [Job](/nimble-sdk/agentic/jobs) can read its input set from an S3 bucket and write its assembled results back to one. Both directions are wired through a single bucket policy that grants Nimble's IAM principal access to specific prefixes. Nimble does not assume a role in the customer account.

Use **Test Connection** in the Job form to verify the policy before saving the job.

## Nimble's IAM principal

Every Job runs under a single IAM user:

```text theme={"system"}
arn:aws:iam::744254827463:user/crawlit-scrapy
```

Use this ARN as the `Principal` in the bucket policy.

## Required permissions

| Prefix                            | Permission                                                                               |
| --------------------------------- | ---------------------------------------------------------------------------------------- |
| `s3://YOUR_BUCKET` (whole bucket) | `s3:ListBucket`                                                                          |
| `s3://YOUR_BUCKET/input/*`        | `s3:GetObject`                                                                           |
| `s3://YOUR_BUCKET/output/*`       | `s3:GetObject`, `s3:PutObject`, `s3:AbortMultipartUpload`, `s3:ListMultipartUploadParts` |

`s3:AbortMultipartUpload` and `s3:ListMultipartUploadParts` are required because large output files are written in parts. If an upload fails mid-way, Nimble aborts the incomplete multipart upload so partial bytes do not accumulate in the bucket.

<Note>
  `s3:DeleteObject` is not requested. Nimble never deletes files in the bucket - including the connection-test probe described below.
</Note>

## Bucket policy template

Replace `YOUR_BUCKET` with the bucket name. Adjust the `input/` and `output/` prefixes to match the paths used in the Job form.

```json theme={"system"}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "NimbleListBucket",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::744254827463:user/crawlit-scrapy" },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::YOUR_BUCKET"
    },
    {
      "Sid": "NimbleReadInputPrefix",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::744254827463:user/crawlit-scrapy" },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::YOUR_BUCKET/input/*"
    },
    {
      "Sid": "NimbleReadWriteOutputPrefix",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::744254827463:user/crawlit-scrapy" },
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:AbortMultipartUpload",
        "s3:ListMultipartUploadParts"
      ],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/output/*"
    }
  ]
}
```

## Applying the policy

<Steps>
  <Step title="Open the bucket">
    In the AWS Console, open **S3** and click the bucket Nimble should access.
  </Step>

  <Step title="Edit the bucket policy">
    Open the **Permissions** tab. Click **Edit** under **Bucket policy**.
  </Step>

  <Step title="Paste the template">
    Paste the JSON above. Replace `YOUR_BUCKET` and the prefixes. Save changes.
  </Step>

  <Step title="Verify in Nimble">
    Open the Job form. Paste the `s3://...` path and click **Test Connection**. A green chip confirms the policy is correct.
  </Step>
</Steps>

<Tip>
  Keep **Block Public Access** enabled. The policy grants access only to Nimble's IAM user, not to the public.
</Tip>

## Test Connection - what it does

| Mode                | Operation                                                                             | Verifies                         |
| ------------------- | ------------------------------------------------------------------------------------- | -------------------------------- |
| Read (input path)   | `head_bucket` + list one object under the prefix                                      | `s3:ListBucket` + `s3:GetObject` |
| Write (output path) | `head_bucket` + `put_object` of an empty `.nimble-connection-test` file at the prefix | `s3:ListBucket` + `s3:PutObject` |

<Note>
  The write test leaves an empty `.nimble-connection-test` file under the output prefix. The file is **not deleted** - the policy does not grant `s3:DeleteObject`, so cleanup is not possible. The key is deterministic, so repeated tests overwrite the same object. At most one residue file per output prefix. Remove it manually at any time.
</Note>

## Interpreting the result

| Chip                              | Meaning                                             | Fix                                    |
| --------------------------------- | --------------------------------------------------- | -------------------------------------- |
| ✓ Connection OK                   | Permissions correct. The prefix has files.          | Ready to use.                          |
| ✓ Connection OK - prefix is empty | Permissions correct. The prefix has no files yet.   | Upload the first input file.           |
| ✗ Access denied                   | The bucket policy is missing a required permission. | Re-apply the template above.           |
| ✗ Bucket does not exist           | The bucket name in the path is wrong.               | Verify the bucket name.                |
| ✗ Connection failed               | Network, throttling, or unexpected S3 error.        | Retry. Contact support if it persists. |

## Related

<CardGroup cols={2}>
  <Card title="All connections" icon="plug" href="/nimble-sdk/agentic/jobs-connections">
    Browse every Job storage connector.
  </Card>

  <Card title="Databricks" icon="https://mintcdn.com/nimble-f5a8283f/xHR1kINYho_Fqe-s/images/icons/databricks.svg?fit=max&auto=format&n=xHR1kINYho_Fqe-s&q=85&s=1a405a4f3e0fb5d7b3e9d1b8fd5607ff" href="/nimble-sdk/agentic/jobs-connections/databricks" width="24" height="24" data-path="images/icons/databricks.svg">
    Connect a Job via Delta Sharing instead.
  </Card>
</CardGroup>
