# EdgeStore Docs: Quick Start
URL: https://edgestore.dev/docs/quick-start
Source: https://raw.githubusercontent.com/edgestorejs/edgestore/refs/heads/main/docs/content/docs/(getting-started)/quick-start.mdx
## Set up with your agent
Read [https://edgestore.dev/SKILL.md](https://edgestore.dev/SKILL.md) and add file uploads to this application.
[Install the skill or connect MCP](/docs/agents).
## Next.js Setup
### Install
npm
pnpm
yarn
bun
```bash
npm install @edgestore/server@rc @edgestore/react@rc
```
```bash
pnpm add @edgestore/server@rc @edgestore/react@rc
```
```bash
yarn add @edgestore/server@rc @edgestore/react@rc
```
```bash
bun add @edgestore/server@rc @edgestore/react@rc
```
### Environment Variables
Copy your project's keys from the [dashboard](https://dashboard.edgestore.dev) to the backend env file:
```sh title=".env.local"
EDGESTORE_ACCESS_KEY=your-access-key
EDGESTORE_SECRET_KEY=your-secret-key
```
Use the app's existing env file, or `.env.local` for a new app. Keep it gitignored.
### Backend
Choose your router below. This bucket's files are accessible to anyone with the link.
<>
```ts title="src/app/api/edgestore/[...edgestore]/route.ts"
import { initEdgeStore } from '@edgestore/server';
import { createEdgeStoreNextHandler } from '@edgestore/server/adapters/next/app';
const es = initEdgeStore.create();
/**
* This is the main router for the EdgeStore buckets.
*/
const router = es.router({
publicFiles: es.fileBucket(),
});
const handler = createEdgeStoreNextHandler({
router,
});
export { handler as GET, handler as POST };
/**
* This type is used to create the type-safe client for the frontend.
*/
export type EdgeStoreRouter = typeof router;
```
```ts title="src/pages/api/edgestore/[...edgestore].ts"
import { initEdgeStore } from '@edgestore/server';
import { createEdgeStoreNextHandler } from '@edgestore/server/adapters/next/pages';
const es = initEdgeStore.create();
/**
* This is the main router for the edgestore buckets.
*/
const router = es.router({
publicFiles: es.fileBucket(),
});
export default createEdgeStoreNextHandler({
router,
});
/**
* This type is used to create the type-safe client for the frontend.
*/
export type EdgeStoreRouter = typeof router;
```
>
### Frontend
Create the React provider:
<>
```ts title="src/lib/edgestore.ts"
'use client';
import { createEdgeStoreProvider } from '@edgestore/react';
import { type EdgeStoreRouter } from '../app/api/edgestore/[...edgestore]/route';
const { EdgeStoreProvider, useEdgeStore } =
createEdgeStoreProvider();
export { EdgeStoreProvider, useEdgeStore };
```
```ts title="src/lib/edgestore.ts"
'use client';
import { createEdgeStoreProvider } from '@edgestore/react';
import { type EdgeStoreRouter } from '../pages/api/edgestore/[...edgestore]';
const { EdgeStoreProvider, useEdgeStore } =
createEdgeStoreProvider();
export { EdgeStoreProvider, useEdgeStore };
```
>
Wrap your app with the provider:
<>
```tsx title="src/app/layout.tsx"
// [!code ++]
import { EdgeStoreProvider } from '../lib/edgestore';
import './globals.css';
// ...
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
{/* [!code ++] */}
{children}
);
}
```
```tsx title="src/pages/_app.tsx"
import '../styles/globals.css';
import type { AppProps } from 'next/app';
// [!code ++]
import { EdgeStoreProvider } from '../lib/edgestore';
export default function App({ Component, pageProps }: AppProps) {
return (
);
}
```
>
### Upload file
You can use the `useEdgeStore` hook to access type-safe frontend client and use it to upload files.
```tsx
'use client';
import * as React from 'react';
import { useEdgeStore } from '../lib/edgestore';
export default function Page() {
const [file, setFile] = React.useState();
const { edgestore } = useEdgeStore();
return (
{
setFile(e.target.files?.[0]);
}}
/>
);
}
```
### Replace file
By passing the `replaceTargetUrl` option, you can replace an existing file with a new one.
It will automatically delete the old file after the upload is complete.
You can also just upload the file using the same file name, but in that case, you might still see the old file for a while because of the CDN cache.
```tsx
const res = await edgestore.publicFiles.upload({
file,
// [!code ++:3]
options: {
replaceTargetUrl: oldFileUrl,
},
});
```
### Delete file
You can delete a file by passing its URL to the `delete` method.
To be able to delete a file from a client component like this, you will need to set the `beforeDelete` [lifecycle hook](/docs/configuration#lifecycle-hooks) on the bucket.
```tsx
await edgestore.publicFiles.delete({
url: urlToDelete,
});
```
Use `deleteMany` to send one request for multiple files. Storage failures are
reported per URL:
```tsx
const result = await edgestore.publicFiles.deleteMany({
urls: selectedFiles.map((file) => file.url),
});
for (const failure of result.failed) {
console.error(failure.url, failure.error.code);
}
```
EdgeStore runs `beforeDelete` for every file before deleting any of them. If
one file is unauthorized, the entire request is rejected without calling the
storage provider. Once authorization succeeds, the provider may still return
partial storage failures in `result.failed`.
### Cancel upload
To cancel an ongoing file upload, you can use an AbortController the same way you would use it to cancel a fetch request.
```tsx
// prepare a state for the AbortController
const [abortController, setAbortController] = useState();
// ...
// instantiate the AbortController and add the signal to the upload method
const abortController = new AbortController();
setAbortController(abortController);
const res = await edgestore.publicFiles.upload({
file,
signal: abortController.signal,
});
// ...
// to cancel the upload, call the controller's abort method
abortController?.abort();
```
When you cancel an upload, an `UploadAbortedError` will be thrown.
You can catch this error and handle it as needed.
For more information, check the [Error Handling](/docs/error-handling) page.
### Transform files before upload
You can transform a file before EdgeStore validates and uploads it by passing
the `transform` option. If the transform keeps the same extension, you can
return the transformed `File` or `Blob` directly. If the transform changes the
file type, return the transformed file with its new extension.
For example, you can convert JPEG and PNG images to WebP before upload:
npm
pnpm
yarn
bun
```bash
npm install browser-image-compression
```
```bash
pnpm add browser-image-compression
```
```bash
yarn add browser-image-compression
```
```bash
bun add browser-image-compression
```
```tsx
import imageCompression from 'browser-image-compression';
const res = await edgestore.publicImages.upload({
file,
options: {
transform: async ({ file, extension, signal }) => {
if (!['image/jpeg', 'image/png'].includes(file.type)) {
return { file, extension };
}
const compressedFile = await imageCompression(file, {
fileType: 'image/webp',
initialQuality: 0.8,
useWebWorker: true,
signal,
});
return {
file: compressedFile,
extension: 'webp',
};
},
},
});
```
If you provide `manualFileName`, EdgeStore will use that exact file name. Make
sure the file name extension matches the transformed file type.
### Temporary files
You can upload temporary files by passing the `temporary` option to the `upload` method.
Temporary files will be automatically deleted after 24 hours if they are not confirmed.
```tsx
await edgestore.publicFiles.upload({
file: fileToUpload,
// [!code ++:3]
options: {
temporary: true,
},
});
```
For forms, upload files as temporary and save their returned IDs/keys and URLs
with your record before confirming them. If the database save fails, leave the
files temporary. Confirmation does not require waiting for hosted processing.
Use the `confirm` method after saving:
```tsx
await edgestore.publicFiles.confirm({
url: urlToConfirm,
});
```
To confirm several temporary files in one request, use `confirmMany`:
```tsx
const result = await edgestore.publicFiles.confirmMany({
urls: temporaryFiles.map((file) => file.url),
});
```
You can check if a file is temporary in the dashboard.
Temporary files are marked with a clock icon.
### Wait for processing
`upload` resolves as soon as the file is transferred. EdgeStore then processes
it in the background, for example to generate an image thumbnail. The file ID
and URL are final right away, so most apps can save them without waiting.
When you need processed details immediately, such as whether the image got a
thumbnail, pass `waitForProcessing`. The upload then resolves with the
processed file, including freshly signed URLs for buckets with
`autoSignedUrls`, and `onPhaseChange` tells you when the transfer finishes and
processing begins.
```tsx
const res = await edgestore.publicImages.upload({
file,
onProgressChange: (progress) => setProgress(progress),
// [!code ++:6]
onPhaseChange: (phase) => {
if (phase === 'processing') setStatus('Processing…');
},
options: {
waitForProcessing: true, // or { timeoutMs: 120_000 }
},
});
```
Processing failures reject with `UploadCanceledError`. If processing takes
longer than `timeoutMs` (60 seconds by default), the upload rejects with
`UploadProcessingTimeoutError`; the file may still finish processing. Both
errors include the file `id`. See [Error Handling](/docs/error-handling).
Waiting for processing does not confirm a [temporary file](#temporary-files).
Confirm it separately once your app decides to keep it.
Providers without background processing, such as S3 and Azure Blob, resolve
once the transfer completes.
## Troubleshooting
If you have any problems using EdgeStore, please check the [Troubleshooting](./troubleshooting) page.
## FAQ
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
EdgeStore is a type-safe file upload solution for React applications. It
provides an easy-to-use API for uploading, managing, and serving files with
features like progress tracking, file validation, and automatic cleanup of
temporary files.
Yes! The EdgeStore Provider has a free plan with generous limits, so you can
get started without any cost. You can also use EdgeStore with your own
infrastructure (like AWS S3 or Azure Blob Storage) if you prefer to manage
your own storage.
The EdgeStore packages (`@edgestore/server`, `@edgestore/react`, etc.) are
open source and released under the MIT license. However, the EdgeStore
Provider (cloud service) is not open source.
EdgeStore supports multiple frameworks including Next.js (App Router and Pages
Router), Astro, Express, Fastify, Hono, Remix, and TanStack Start. Check the
[Adapters](/docs/adapters/next) section for setup guides.
By default, EdgeStore accepts most common file types. You can customize
allowed file types and maximum file sizes per bucket using the `accept` and
`maxSize` options. See the [Configuration](/docs/configuration) page for
details.
Yes! EdgeStore supports AWS S3, Azure Blob Storage, and custom providers in
addition to EdgeStore Cloud. Check the [Providers](/docs/providers/edgestore)
section for setup instructions.
EdgeStore is not recommended for real-time streaming of large files like
videos and audio. It's optimized for file uploads and serving static files,
not for streaming use cases. For video/audio streaming, consider using a
dedicated streaming service or CDN.