> ## 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.

# Go SDK: upload and commit files

> Create applications from a zip with c.Apps.Create and send files to an existing application with c.Apps.Commit, streamed from any io.Reader.

Each snippet below runs on its own inside this program: paste one at a time into `main` and run `goimports` (see [Running the examples](/en/sdks/go/client#running-the-examples)).

```go theme={"system"}
package main

import (
	"context"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

var (
	ctx   = context.Background()
	c     = squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
	appID = "abc123def456abc123def456"
)

func main() {
	// Paste one snippet here, then run goimports.
}
```

## Accepted inputs

`Apps.Create` and `Apps.Commit` take any `io.Reader` and stream it as `multipart/form-data`, never loading it into memory:

| Input | Notes |
| - | - |
| `*os.File` | Streamed from disk with a `Content-Length`. Its base name is used as the filename. Can be retried on 503 `UPLOAD_BUSY` |
| `*bytes.Reader`, `*strings.Reader` (any `io.ReaderAt` that is also an `io.Seeker`) | Sent with a `Content-Length`. Can be retried on 503 `UPLOAD_BUSY` |
| Any other `io.Reader` (a pipe, a response body, ...) | Sent chunked, in a single attempt: it cannot be replayed |

Uploads are **limited to 100 MB**. A larger file fails locally with `FILE_TOO_LARGE` (status `0`): before anything is sent when the size is known, otherwise as soon as the stream passes 100 MB. Uploads have **no default deadline**: cancel them with `ctx`.

## Creating an application

`Apps.Create(ctx, zip)` deploys a `.zip` that contains a [`squarecloud.app`](/en/getting-started/config-file) configuration file at its root.

```go theme={"system"}
f, err := os.Open("bot.zip")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

app, err := c.Apps.Create(ctx, f)
if err != nil {
	log.Fatal(err)
}

fmt.Println(app.ID, app.Name, app.RAM, app.CPU, app.Language.Name, app.Language.Version)
fmt.Println(app.Domain)  // "<subdomain>.squareweb.app" for web apps, "" otherwise
fmt.Println(app.Cluster) // the cluster the app was placed on
```

| Field | Description |
| - | - |
| `ID` (`id`) | The new app's id |
| `Name` (`name`) | Name from the config file |
| `Description` (`description`) | `""` when not set |
| `Domain` (`domain`) | Full `<subdomain>.squareweb.app` host; `""` for non-web apps |
| `Cluster` (`cluster`) | Cluster the app was placed on |
| `RAM` / `CPU` (`ram` / `cpu`) | Allocated resources (`CPU` is a `float64`) |
| `Language` (`language`) | `Name` and `Version` |

## Committing to an application

`Apps.Commit(ctx, appID, r, path, filename)` uploads a file into an existing app:

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

The filename is `filename`, else the reader's own name (the base name of an `*os.File`), else `commit.zip`. Pass `""` to use the default.

```go theme={"system"}
// Unpack a zip at the root
build, err := os.Open("build.zip")
if err != nil {
	log.Fatal(err)
}
defer build.Close()
if err := c.Apps.Commit(ctx, appID, build, "", ""); err != nil {
	log.Fatal(err)
}

// Unpack a zip into /src
patch, err := os.Open("patch.zip")
if err != nil {
	log.Fatal(err)
}
defer patch.Close()
if err := c.Apps.Commit(ctx, appID, patch, "/src", ""); err != nil {
	log.Fatal(err)
}

// A single file from memory: /src/index.js
code := strings.NewReader(`console.log("Hello from Square Cloud");`)
if err := c.Apps.Commit(ctx, appID, code, "/src", "index.js"); err != nil {
	log.Fatal(err)
}
```

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

## Cancelling an upload

```go theme={"system"}
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()

f, err := os.Open("bot.zip")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

_, err = c.Apps.Create(ctx, f)
if errors.Is(err, context.DeadlineExceeded) {
	fmt.Println("the upload took too long")
}
```

A canceled upload returns an `*APIError` (`NETWORK_ERROR` when `ctx` was canceled, `TIMEOUT` when its deadline passed) that unwraps to `context.Canceled` or `context.DeadlineExceeded`.

## 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 when the reader can be replayed |

Opening the file is up to your code, so an `os.Open` error never reaches the SDK. A `nil` reader returns a plain error, not an `*APIError`. See [Errors](/en/sdks/go/errors) for the full list.

## Next steps

<CardGroup cols={3}>
  <Card title="Managing files" icon="folder-open" href="/en/sdks/go/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.