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

# Python SDK: upload and commit files

> Create applications from a zip with apps.create() and send files to an existing application with apps.commit(), from a path, bytes or a binary file object.

Examples use the `client` from [Creating the client](/en/sdks/py/client#creating-the-client). `app_id` is the id of one of your apps: [`client.account.me()`](/en/sdks/py/client#account) lists them.

## Accepted inputs

`apps.create()` and `apps.commit()` take:

| Input | Notes |
| - | - |
| A file path (`str` or `os.PathLike`) | Streamed from disk, never read into memory. The file's name is used as the filename |
| `bytes` (or `bytearray`, `memoryview`) | Sent from memory |
| A binary file object (`open(path, "rb")`, `io.BytesIO`, ...) | A seekable file is streamed from its current position; its `name`, if any, is used as the filename. A non-seekable one (a pipe) is read into memory first |

Uploads are **limited to 100 MB**. A larger file fails locally with `FILE_TOO_LARGE` (status `0`) before anything is sent. Uploads are streamed and have **no timeout** once connected (see [Timeouts](/en/sdks/py/client#timeouts)).

## Creating an application

`apps.create(file)` deploys a `.zip` that contains a [`squarecloud.app`](/en/getting-started/config-file) configuration file at its root. `bytes` and unnamed file objects are sent as `app.zip`.

```python theme={"system"}
app = client.apps.create("./bot.zip")

print(app["id"], app["name"], app["ram"], app["cpu"], app["language"]["name"], app["language"]["version"])
print(app.get("domain"))  # "<subdomain>.squareweb.app" for web apps, absent otherwise
print(app.get("cluster"))  # the cluster the app was placed on
```

| Field | Description |
| - | - |
| `id` | The new app's id |
| `name` | Name from the config file |
| `description` | Present only when set |
| `domain` | Full `<subdomain>.squareweb.app` host; absent for non-web apps |
| `cluster` | Cluster the app was placed on |
| `ram` / `cpu` | Allocated resources |
| `language` | `{ name, version }` |

## Committing to an application

`apps.commit(app_id, file, path=None, filename=None)` uploads a file into an existing app. `path` and `filename` are keyword-only.

* A `.zip` is **unpacked** at `path` (the app root by default).
* Any other file lands at `path/<filename>`.

The filename is `filename`, else the file's own name (path or file object), else `commit.zip`.

```python theme={"system"}
# Unpack a zip at the root
client.apps.commit(app_id, "./build.zip")

# Unpack a zip into /src
client.apps.commit(app_id, "./patch.zip", path="/src")

# A single file from memory: /src/index.js
client.apps.commit(app_id, code.encode(), path="/src", filename="index.js")
```

A commit does not restart the app. Call [`apps.restart()`](/en/sdks/py/managing_application#start-stop-and-restart) to apply it.

## Cancelling an upload

Python uploads cannot be cancelled once sent: `apps.create()` and `apps.commit()` have no `signal` or cancel argument, and no timeout once connected. The connect itself is bounded by `timeout`.

To keep the rest of your program responsive during a long upload, run it with `AsyncSquareCloud` (it runs in a worker thread) or in your own thread:

```python theme={"system"}
async with AsyncSquareCloud(os.environ["SQUARECLOUD_API_KEY"]) as client:
    app = await client.apps.create("./bot.zip")
```

## Errors

| Status | Code | When |
| - | - | - |
| 0 | `FILE_TOO_LARGE` | The file is over 100 MB (checked locally) |
| 400 | `INVALID_FILE`, `INVALID_FILENAME` | No file, or a file name with path separators, `..` or control characters |
| 400 | `INVALID_PATH` | `path` contains traversal or shell metacharacters (commit) |
| 400 | `INSUFFICIENT_MEMORY` | Less than 256 MB of available memory on the plan (create) |
| 400 | `COMMIT_FAILED` | The commit could not be applied (commit) |
| 400 | `UPLOAD_FAILED`, `STORAGE_UPLOAD_FAILED`, `CLUSTER_SELECTION_FAILED` | The upload could not be processed (create) |
| 503 | `CLUSTER_MAINTENANCE_TRY_LATER` | Provisioning is paused for maintenance (create) |
| 503 | `UPLOAD_BUSY` | Too many uploads in progress: retried automatically |

A local path that cannot be opened (or a file that becomes unreadable mid-upload) raises an `OSError`, not a `SquareCloudAPIError`. A missing path fails before anything is sent. See [Errors](/en/sdks/py/errors) for the full list.

## Next steps

<CardGroup cols={3}>
  <Card title="Managing files" icon="folder-open" href="/en/sdks/py/managing_files">
    List, read, write, move and delete app files.
  </Card>

  <Card title="Upload API reference" icon="code" href="/en/api-reference/endpoint/apps/upload">
    The REST endpoints behind these methods.
  </Card>

  <Card title="Upload from the CLI" icon="terminal" href="/en/cli-reference/deploy">
    The same actions from the terminal.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.