---
title: File Uploading
banner:
  content: |
    ⚠️ Open SaaS is now running on <a href='https://wasp-lang.dev'>Wasp v0.13</a>! If you're running an older version of Open SaaS, please follow the 
    <a href="https://wasp-lang.dev/docs/migrate-from-0-12-to-0-13">migration instructions here</a> ⚠️ 
---

This guide will show you how to set up file uploading in your SaaS app.

There are two options we recommend:
1. Using [AWS S3](https://aws.amazon.com/s3/) with presigned URLS for secure file storage
2. Using Multer middleware to upload files to your own server

**We recommend using AWS S3 as it's a scalable, secure option, that can handle a large amount of storage.** 

If you're just looking to upload small files and don't expect your app to grow to a large scale, you can use Multer to upload files to your app's server.

:::tip[Star our Repo on GitHub! 🌟]
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!

If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
:::

## Using AWS S3

### How presigned URLs work

Presigned URLs are URLs that have been signed with your AWS credentials and can be used to upload files to your S3 bucket. They are time-limited and can be generated on the server and sent to the client to upload files directly to S3.

The process of generating a presigned URL is as follows:
1. The client sends a request to the server to upload a file
2. The server generates a presigned URL using its AWS credentials
3. The server sends the presigned URL to the client
4. The client uses the presigned URL to upload the file directly to S3 before the URL expires

We use this method to upload files to S3 because it is more secure than uploading files directly from the client to S3. It also allows us to keep our AWS credentials private and not expose them to the client.

To use presigned URLs, we'll need to set up an S3 bucket and get our AWS credentials.

### Create an AWS Account

Before you begin, you'll need to create an AWS account. AWS accounts are free to create and are split up into:
1. Root account
2. IAM users

You'll need to first create a root account, and then an IAM user for your SaaS app before you can start uploading files to S3.

To do so, follow the steps in this external guide: [Creating IAM users and S3 buckets in AWS](https://medium.com/@emmanuelnwright/create-iam-users-and-s3-buckets-in-aws-264e78281f7f)

### Create an AWS S3 Bucket

Once you are logged in with your IAM user, you'll need to create an S3 bucket to store your files.

1. Navigate to the S3 service in the AWS console
![find s3](/file-uploads/find-s3.png)
2. Click on the `Create bucket` button
![create bucket](/file-uploads/create-bucket.png)
3. Fill in the bucket name and region
4. **Leave all the settings as default** and click `Create bucket`
![bucket settings](/file-uploads/default-settings.png)

### Change the CORS settings

Now we need to change some permissions on the bucket to allow for file uploads from your app.

1. Click on the bucket you just created
![new bucket](/file-uploads/new-bucket.png)
2. Click on the `Permissions` tab
![permissions](/file-uploads/permissions.png)
3. Scroll down to the `Cross-origin resource sharing (CORS)` section and click `Edit`
![cors](/file-uploads/cors.png)
5. Paste the following CORS configuration and click `Save changes`:
```json
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT",
            "GET"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]
```

### Get your AWS S3 credentials

Now that you have your S3 bucket set up, you'll need to get your S3 credentials to use in your app.

1. Click on your username in the top right corner of the AWS console and select `Security Credentials`
![security credentials](/file-uploads/username.png)
2. Scroll down to the `Access keys` section
3. Click on `Create Access Key`
4. Select the `Application running on an AWS service` option and create the access key
![access key](/file-uploads/keys.png)
5. Copy the `Access key ID` and `Secret access key` and paste them in your `src/app/.env.server` file: 
```sh
  AWS_S3_IAM_ACCESS_KEY=ACK...
  AWS_S3_IAM_SECRET_KEY=t+33a...
  AWS_S3_FILES_BUCKET=your-bucket-name
  AWS_S3_REGION=your-region // (e.g. us-west-2)
```

:::tip[Star our Repo on GitHub! 🌟]
We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free!

If you're finding this template and its guides useful, consider giving us [a star on GitHub](https://github.com/wasp-lang/wasp)
:::

### Using and Customizing File Uploads with S3 in your App

With your S3 bucket set up and your AWS credentials in place, you can now start uploading files in your app using presigned URLs by navigating to `localhost:3000/file-upload` and uploading a file.

To begin customizing file uploads, is important to know where everything lives in your app. Here's a quick overview:
- `main.wasp`:
  - The `File entity` can be found here. Here you can modify the fields to suit your needs:
    ```c
      entity File {=psl
        id                        String          @id @default(uuid())
        name                      String
        type                      String
        key                       String
        uploadUrl                 String
        user                      User            @relation(fields: [userId], references: [id])
        userId                    Int
        createdAt                 DateTime        @default(now())
      psl=}
    ```
- `src/server/actions.ts`:
  - The `createFile` action lives here and calls the `getUploadFileSignedURLFromS3` within it using your AWS credentials before passing it to the client. This function stores the files in the S3 bucket within folders named after the user's ID, so that each user's files are stored separately.
- `src/server/queries.ts`:
  - The `getAllFilesByUser` fetches all File information uploaded by the user. Note that the files do not exist in the app database, but rather the file data, name its `key`, which is used to fetch the file from S3
  - The `getDownloadFileSignedURL` query fetches the presigned URL for a file to be downloaded from S3 using the file's `key` stored in the app's database
- `src/client/app/FileUploadPage.tsx`:
  - The `FileUploadPage` component is where the file upload form lives. It also allows you to download the file from S3 by calling the `getDownloadFileSignedURL` based on that files `key` in the app DB. 

## Using Multer to upload files to your server

If you're looking to upload files to the app server, you can use the Multer middleware to handle file uploads. This will allow you to store files on your server and is a good option if you need a quick and dirty, free solution for simple file uploads.

Below are GitHub Gists that show you how to set up file uploads using Multer in your app:

### Wasp version 0.12 & higher

<script src="https://gist.github.com/infomiho/ec379df4e33f3ae3410a251ba3aa81af.js"></script>
