# Files

> Upload and download files programmatically.

**URL:** https://inference.sh/docs/api/sdk/files
**Last updated:** 2026-10-11

---

Upload and download files programmatically.

---

## Automatic Upload

Local file paths and data URIs are uploaded automatically:

<div data-type="codegroup">

```python Python
result = client.tasks.run({
    "app": "image-processor",
    "input": {
        "image": "/path/to/image.png"  # Uploaded automatically
    }
})
```

```typescript JavaScript
const result = await client.run({
  app: 'image-processor',
  input: {
    image: 'data:image/png;base64,...'  // Uploaded automatically
  }
});
```

</div>

---

## Manual Upload

<div data-type="codegroup">

```python Python
from inferencesh import UploadFileOptions

# Upload from path
file_obj = client.files.upload("/path/to/image.png")
print(f"URI: {file_obj['uri']}")

# Upload from bytes
file_obj = client.files.upload(
    b"raw bytes data",
    UploadFileOptions(
        filename="data.bin",
        content_type="application/octet-stream"
    )
)

# Upload with options
file_obj = client.files.upload(
    "/path/to/image.png",
    UploadFileOptions(
        filename="custom_name.png",
        content_type="image/png",
        public=True  # Make publicly accessible
    )
)
```

`client.upload_file()` is a legacy alias for `client.files.upload()`. The async client uses the same call shape — including local paths, bytes, data URIs, and base64 strings:

```python
file_obj = await client.files.upload("/path/to/image.png")
```

```typescript JavaScript
// From Base64
const file = await client.uploadFile('data:image/png;base64,...', {
  filename: 'image.png',
  contentType: 'image/png'
});

console.log('URI:', file.uri);

// From Blob (Browser)
const blob = new Blob([arrayBuffer], { type: 'image/png' });

const file = await client.uploadFile(blob, {
  filename: 'image.png'
});
```

```swift Swift
let file = try await client.files.upload(
    imageData,
    filename: "image.png",
    contentType: "image/png"
)

print(file.uri)
```

</div>

### Data URI formats (JavaScript)

`client.files.upload()` and automatic upload in `client.run()` accept standard [data URIs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs):

| Format | Example | Notes |
|--------|---------|-------|
| Base64 | `data:image/png;base64,iVBORw0KGgo=` | Default for binary payloads |
| URL-encoded | `data:text/plain,Hello%20World` | Decoded with `decodeURIComponent` before upload |
| URL-safe base64 | `data:text/plain;base64,SGVsbG8` | `-` and `_` are normalized to `+` and `/` |
| Omitted media type | `data:;base64,SGVsbG8=` | Defaults to `text/plain` |

Invalid data URIs throw `Invalid data URI format`. If the API does not return `upload_url` for a created file record, or the PUT to that URL fails, upload rejects with a clear error.

When `processInput` walks task `input`, it uploads `data:` strings anywhere in nested objects and replaces them with `inf://files/...` URIs. Short plain strings (for example `"hello"` or API keys under 64 characters) are left unchanged — only `data:` URIs or long base64-looking strings are treated as file content.

---

## Upload Options

<div data-type="codegroup">

```python Python
from inferencesh import UploadFileOptions

UploadFileOptions(
    filename="custom.png",     # File name
    content_type="image/png",  # MIME type
    path="/custom/path",       # Custom storage path
    public=True                # Make publicly accessible
)
```

```typescript JavaScript
interface UploadFileOptions {
  filename?: string;     // File name
  contentType?: string;  // MIME type
  path?: string;         // Custom storage path
  public?: boolean;      // Make publicly accessible
}
```

</div>

---

## Use Uploaded Files

<div data-type="codegroup">

```python Python
file = client.files.upload("/path/to/image.png")

result = client.tasks.run({
    "app": "image-processor",
    "input": {"image": file["uri"]}
})
```

```typescript JavaScript
const file = await client.uploadFile(data, { filename: 'image.png' });

const result = await client.run({
  app: 'image-processor',
  input: { image: file.uri }
});
```

```swift Swift
let file = try await client.files.upload(data, filename: "image.png", contentType: "image/png")

let task = try await client.tasks.run(ApiAppRunRequest(
    app: "image-processor",
    input: ["image": .string(file.uri)]
))
```

</div>

---

## Agent file attachments

When chatting with agents, attach files on `send_message` / `sendMessage`:

<div data-type="codegroup">

```python Python
response = agent.send_message(
    "Describe this image",
    files=[open("image.png", "rb").read()],
)

# upload_file on the agent returns a FileRef (uri, filename, content_type)
ref = agent.upload_file(open("doc.pdf", "rb").read(), filename="doc.pdf")
response = agent.send_message("Summarize", files=[open("doc.pdf", "rb").read()])
```

```typescript JavaScript
await agent.sendMessage('Describe this image', {
  files: [imageBlob],  // Blob, data URI, or existing FileRef
});
```

</div>

Files are uploaded via the Files API and referenced in the message `input.attachments` field (Python) or `input.images` / `input.files` (JavaScript `client.agent().sendMessage()`). The React `AgentChatProvider` posts them as `attachments` on `POST /chats/{id}/messages` (**@inferencesh/sdk ≥ v0.22.1**).

→ [Template agents](/docs/api/agent/template#file-attachments) · [Python SDK](/docs/api/sdk-python#file-attachments) · [JavaScript SDK](/docs/api/sdk-javascript#file-attachments)

---

## Download Results

<div data-type="codegroup">

```python Python
import requests

result = client.tasks.run(params)
output_url = result["output"]["image"]["uri"]

# Download
response = requests.get(output_url)
with open("output.png", "wb") as f:
    f.write(response.content)
```

```typescript JavaScript
const result = await client.run(params);
const outputUrl = result.output.image.uri;

// Download
const response = await fetch(outputUrl);
const blob = await response.blob();
```

```swift Swift
let task = try await client.tasks.run(params)

// Apps return a bare URL or {"uri": ...}
if let uri = task.output["image"]?["uri"]?.stringValue, let url = URL(string: uri) {
    // Download
    let data = try await client.download(url)
}
```

</div>

---

## File Class (App Development)

When building apps in Python, use the `File` class:

```python
from inferencesh import File

# From path
file = File(path="/path/to/file.png")

# With metadata
file = File(
    path="/path/to/file.png",
    content_type="image/png",
    filename="custom.png"
)

# Check existence
if file.exists():
    print(f"Size: {file.size} bytes")
```
