# Upload Store (https://v1.s3.dimah.dev/docs/react/upload-store)

An `UploadStore` persists multipart metadata, not the browser `File`. After a
reload, the user reselects the same local file and the client uses the stored
identity to reconcile parts and resume.

```ts title="lib/upload-store.ts"
import { createLocalStorageStore } from "@dimah-s3/react";

export const localStorageStore = createLocalStorageStore();
```

```tsx title="app/video-uploader.tsx"
"use client";

import { useUpload } from "@dimah-s3/react";
import { localStorageStore } from "@/lib/upload-store";

export function VideoUploader() {
  const upload = useUpload({
    route: "video",
    multipart: true, // [!code ++]
    uploadStore: localStorageStore, // [!code ++]
  });

  return (
    <div
      {...upload.getRootProps()}
      className="cursor-pointer rounded border p-4 text-center"
    >
      <input {...upload.getInputProps()} />
      {upload.isUploading
        ? `Uploading: ${upload.progress.percent}%`
        : "Upload large video"}
    </div>
  );
}
```

The resume key is derived as
`${route}:${file.name}:${file.size}:${file.lastModified}`. It is a lookup key,
not a collision-resistant hash.

---

## Built-in stores [#built-in-stores]

- **`createLocalStorageStore()`** — persists multipart metadata in browser `localStorage` across page reloads.
- **`createMemoryStore()`** — in-memory store for unit tests or SSR.

```ts
import { createLocalStorageStore, createMemoryStore } from "@dimah-s3/react";

const memoryStore = createMemoryStore();
const localStore = createLocalStorageStore();
```

---

## Custom upload store interface [#custom-upload-store-interface]

```ts
import type { UploadStore } from "@dimah-s3/react";
```

<AutoTypeTable
  path="packages/react/src/types/upload-store.ts"
  name="UploadStore"
/>

## Frequently asked questions [#frequently-asked-questions]

<Accordions>

<Accordion title="Does @dimah-s3/db replace an upload store?">

No. [`@dimah-s3/db`](https://v1.s3.dimah.dev/docs/db) tracks pending uploads on the server, while an
`UploadStore` maps a browser-side resume identity to the S3 key and upload ID.
Use `createLocalStorageStore()` for same-browser reloads, or implement the
[custom store interface](#custom-upload-store-interface) with your own API for
cross-device metadata lookup. In either case, the browser still needs the user
to select the same local file.

</Accordion>

<Accordion title="When should I enable an upload store?">

Enable `uploadStore` for large multipart uploads that users may need to resume
after a refresh or lost connection. After a reload they must reselect the same
file. Small, single-part uploads do not need a store.

</Accordion>

</Accordions>
