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

# Basic File Upload

> Accept a single file upload with Formbase.

Formbase accepts file uploads through `multipart/form-data` and stores the file in your configured S3-compatible bucket. The submission data will include a URL under either `file` or `image` depending on the MIME type.

If you are self-hosting, make sure storage credentials are configured before enabling file uploads.

<Steps>
  <Step title="Configure storage">
    Set the `STORAGE_*` environment variables so Formbase can connect to your bucket. See [File storage](/self-hosting/file-storage) for examples.
  </Step>

  <Step title="Add a file input">
    ```html theme={null}
    <form
      action="https://formbase.dev/s/YOUR_FORM_ID"
      method="POST"
      enctype="multipart/form-data"
    >
      <input name="name" type="text" required />
      <input name="resume" type="file" />
      <button type="submit">Upload</button>
    </form>
    ```

    The browser will submit the file as `multipart/form-data`.
  </Step>

  <Step title="Check the submission">
    In the dashboard, the uploaded file appears as a clickable URL under `file` or `image`.

    <Frame>
      <img src="https://mintcdn.com/formbase/gA9p3Ks8sQ18Mo1W/images/submissions-table.png?fit=max&auto=format&n=gA9p3Ks8sQ18Mo1W&q=85&s=88d55a8e43f0534809a399f133d59e34" alt="Submissions table with file URLs" width="1280" height="720" data-path="images/submissions-table.png" />
    </Frame>
  </Step>
</Steps>

## JavaScript submission

If you need a custom UI, submit with fetch and `FormData`:

```js theme={null}
const response = await fetch('https://formbase.dev/s/YOUR_FORM_ID', {
  method: 'POST',
  body: new FormData(formElement),
  redirect: 'manual',
});

if (response.status === 303 || response.ok) {
  // success
}
```

<Callout type="note">
  Formbase stores uploaded files as signed URLs. The original filename is not preserved.
</Callout>
