Upload Routes
Upload routes are where you define how files are uploaded. To define a route, use the route
function.
You can create multiple routes for different purposes (e.g. images, videos).
Here is a basic example of a single file upload route:
import { route } from 'better-upload/server';
route({
fileTypes: ['image/*'], // Accepts all image types
maxFileSize: 1024 * 1024 * 4, // 4MB
});
Single file routes have the following options:
Prop | Type | Default |
---|---|---|
fileTypes? | string[] | All file types allowed |
maxFileSize? | number | 5242880 (5MB) |
signedUrlExpiresIn? | number | 120 (2 minutes) |
clientMetadataSchema? | object | - |
Callbacks
When defining a route, you may want to run code before or after the upload. You can do this by using the callbacks.
Before upload
The onBeforeUpload
callback is called before the pre-signed URL is generated. Use this to run custom logic before uploading a file, such as auth and rate-limiting.
The request, file, and metadata sent from the client are available.
route({
onBeforeUpload: async ({ req, file, clientMetadata }) => {
const user = await auth();
if (!user) {
throw new UploadFileError('Not logged in!');
}
return {
objectKey: user.id,
bucketName: 'another-bucket',
};
},
});
Rejecting uploads
Throw UploadFileError
to reject the file upload. This will also send the
error message to the client.
You can return an object with the following properties:
Prop | Type | Default |
---|---|---|
objectKey? | string | - |
objectMetadata? | Record<string, string> | - |
metadata? | object | - |
bucketName? | string | - |
After generating pre-signed URL
The onAfterSignedUrl
callback is called after the pre-signed URL is generated. Use this to run custom logic after the URL is generated, such as logging and saving data.
In addition to all previous data, metadata from the onBeforeUpload
callback is also available.
route({
onAfterSignedUrl: async ({ req, file, metadata, clientMetadata }) => {
// the file now has the objectKey property
return {
metadata: {
example: '123',
},
};
},
});
You can return an object with the following properties:
Prop | Type | Default |
---|---|---|
metadata? | object | - |
Multipart uploads
If you want to upload files larger than 5GB, you need to use multipart uploads. To enable it, set multipart
to true
. It works both for single and multiple files. No change is needed in the client.
route({
multipleFiles: true,
multipart: true,
partSize: 1024 * 1024 * 20, // 20MB, default is 50MB
});
You can now also modify the following options:
Prop | Type | Default |
---|---|---|
partSize? | number | 52428800 (50MB) |
partSignedUrlExpiresIn? | number | 1500 (25 minutes) |
completeSignedUrlExpiresIn? | number | 1800 (30 minutes) |
Even for files under 5GB, using multipart uploads can speed up the upload process. Empty files (0 bytes) will fail to upload with multipart uploads.
Router
The router is where all upload routes are defined. To define a router, create an object with the Router
type.
import { type Router } from 'better-upload/server';
export const router: Router = {
client: s3,
bucketName: 'my-bucket',
routes: {
// your routes...
},
};