Add Object Storage to your app

Upload large files to bucket in your Webflow Cloud app

This guide will show you how to add Object Storage to your project and use it to store and serve files. You’ll learn how to set up an Object Storage binding, list and display files from your bucket, upload files to your bucket with proper validation, and handle large file uploads using multipart uploads.

Object Storage for Webflow Cloud is in Beta

To continue with this tutorial, you’ll need access to Object Storage for Webflow Cloud.

Prerequisites

Before you begin, make sure you have:

  • Access to the Webflow Cloud Storage Beta
  • A GitHub account
  • A code editor like Cursor or VS Code
  • Node.js 20+ and npm 10+
  • Basic familiarity with JavaScript/TypeScript

Set up your project

This tutorial uses a repository with pre-built UI, backend endpoints, and helper utilities for file uploads and management. Follow along with the steps below and reference the code in the example project to see how Object Storage is used in this Webflow Cloud app. You may need to make some code changes to the project to get it working with your Webflow Cloud environment.

1

Fork and clone the example repository

To start, fork the project on Github so you have your own copy to work with.

Next, clone your fork of the starter repository to your local machine and install dependencies:

$git clone https://github.com/<YOUR-GITHUB-USERNAME>/webflow-cloud-object-storage.git
>cd webflow-cloud-object-storage
>npm install

The project uses Astro with TypeScript and includes all necessary dependencies for Object Storage operations.

2

Create a new Webflow Cloud project

Go to the Webflow Cloud dashboard in your site settings and create a new Webflow Cloud project.

  1. Go to your Webflow Cloud dashboard
  2. Click “Install Github app” to authorize Webflow Cloud for your fork of this repo - follow the prompts on Github
  3. Click “Create new project”
  4. Name your project
  5. Choose the webflow-cloud-object-storage repository
  6. Click “Create project”
Repository linking

Once the project is created, it will automatically deploy when you push changes to the linked GitHub repository.

3

Create an environment

Create a new environment for the main branch

  1. In the same modal, choose the main branch
  2. Choose a mount path for the environment (for example, /app → mysite.webflow.io/app)
  3. Click “Create environment”
  4. Publish your Webflow site to make your environment live
  5. A new row should appear in the table with your new environment. Click into it to see the environment details
Mount paths

Mount paths are unique to each environment and are used to route traffic to the correct environment. Each mount path must be unique across all environments within a project.

4

Add environment variables

On your environment page, click the “Environment Variables” tab and add the following environment variable:

  • Variable Key: ORIGIN
  • Variable Value: Your Webflow Cloud domain (for example, https://your-site-name.webflow.io)

Click “Add variable” to save the variable.

5

Update your project configuration

Now, with your locally cloned project, open it in your preferred code editor and update the following files:

  • astro.config.mjs to include the base path for your environment and the assetsPrefix to match the mount path of your environment.
  • Create a new .env file at the root of the project to include the ORIGIN environment variable.
1export default defineConfig({
2 base: "/YOUR_MOUNT_PATH",
3 build: {
4 assetsPrefix: "/YOUR_MOUNT_PATH",
5 },
6
7 // Additional configuration options...
8});

Add Object Storage binding

Before you can use Object Storage in your Webflow Cloud app, you need to declare a binding in your project’s configuration. This binding tells your app how to connect to the storage resource.

Once the binding is declared, your app can use simple methods like .list(), .put(), and .delete() to read from and write to the Object Storage bucket directly in your code.

1

Declare a binding in wrangler.json

Open your project’s wrangler.json file and add an r2_buckets array to define your Object Storage buckets with the following information:

  • binding: The variable name you’ll use to access the bucket in your code. This must be a valid JavaScript variable name.
  • bucket_name: The name of the bucket wher you’ll store files
wrangler.json
1{
2 "r2_buckets": [
3 {
4 "binding": "CLOUD_FILES",
5 "bucket_name": "cloud-files"
6 }
7 ]
8 }
2

Generate type definitions for your binding.

Update your project’s type definitions to enable autocomplete and type safety:

$npx wrangler types

This ensures your code editor recognizes the Object Storage binding.

3

Deploy your app

Commit and push any local changes to your remote Github repo to automatically deploy your app.

CLI deployments will not apply changes to binding configurations

To create a new binding, you’ll need to commit and push your changes to your linked repository.

4

Access your binding in your Environment Dashboard

In Webflow, navigate to your site’s settings and click on the “Webflow Cloud” tab. Navigate to your project’s environment dashboard. Once your project is deployed, you’ll see a “Bindings” tab appear in the dashboard.

Bindings tab in Webflow Cloud environment dashboard

Click on the “Bindings” tab and you’ll see your Object Storage binding listed.

5

Add test files to your bucket

Add a couple of test files to your bucket using the Webflow Cloud dashboard. Click on the “Upload” button and select the files you want to upload. Later, you’ll create a route to upload files to your bucket.

Upload files to Object Storage bucket

You’ll see the file appear in your bucket in the dashboard.

In your local project, you can upload files to a local bucket by running the following command in your terminal:

$npx wrangler r2 object put <YOUR_BUCKET_NAME>/<YOUR_FILE_NAME> --file=<PATH_TO_YOUR_FILE>

This will upload the file to your local bucket, which you can then access when developing your project.

List files in your bucket

Get familiar with accessing your Object Storage bucket in your code by creating a new route that lists the files in your bucket. This route will return all files stored in your bucket with their metadata.

1

Create an API directory

In your project’s src/pages directory, create an api directory.

2

Create a list files route

In your api directory, create a new file called list-assets.ts. This file will contain the logic for listing the files in your bucket.

Serve files from your bucket

Now that you can list files, create a route to serve individual files from your bucket. This route will handle file requests and return the file content with appropriate headers.

1

Create a file serving route

In your api directory, create a new file called asset.ts. This file will contain the logic for serving individual files from your bucket.

2

(Optional) View files in your app

If you added assets to your local bucket in your local project, you can view them now.

To see your app locally, run the following command:

$npm run dev

This will start the development server and you can view your app at http://localhost:4321/YOUR_BASE_PATH.

You should see the files you added to your bucket appear in the list of files.

View files in your app
3

Deploy your app

To deploy your app to Webflow Cloud, commit and push your changes to your GitHub repository.

$git add .
>git commit -m "Add asset endpoints"
>git push

Go to your environment in Webflow Cloud to see your app deployed. Once deployed, you can access your app at https://<YOUR_DOMAIN>/<YOUR_BASE_PATH> and see the files you uploaded via the Webflow Cloud dashboard.

To upload files from the App, you’ll create a new upload route in the next step.

Upload files to your bucket

Next you’ll walk through the route to handle file uploads from your frontend. This route will process form data, validate files, and store them in your bucket. This approach is best for smaller files less than 1MB. For larger files, see the multipart upload route in the next section.

File uploads should be executed on the domain of your worker

To avoid size upload limits, file upload endpoints should be executed on the domain of your worker using the ASSETS_PREFIX environment variable, and not your custom Webflow Cloud domain. Because of this, you’ll need to handle CORS requests for this route.

1

Create an upload route

In your api directory, step into the file called upload.ts. This file will contain the logic for uploading files to your bucket.

2

Test your upload route

The frontend is already set up to use the upload route. You can test it by navigating to the file uploader page and uploading a file in your development environment. You should see the file appear in the list of files.

3

Deploy your app

Deploy your app to Webflow Cloud to start uploading files from the frontend. Commit and push your changes to your GitHub repository to start a deployment.

$git add .
>git commit -m "Add upload endpoints"
>git push

Once your app is deployed, navigate to the file uploader page and upload a file. You should see the file appear in the list of files.

Test your upload route

You may see a 413 Content Too Large error if you attempt to upload large files. For these cases, see the multipart upload route in the next section.


Handle large files with multipart uploads

Webflow Cloud apps have a 500MB request body limit and require requests to complete within 30 seconds. The direct upload approach from the previous section is good for small files. For larger files, use the multipart upload approach shown below.

Multipart uploads break large files into smaller chunks that can be uploaded concurrently, improving upload performance and reliability. This approach allows browsers to upload multiple parts simultaneously and resume interrupted uploads. To achieve this, you’ll need to set up logic on both the server and the browser to handle the multipart upload process.

Create the server endpoints

The server handles three main operations:

  • Create - Initialize upload session and get upload ID from the bucket
  • Upload Parts - Accept individual file chunks
  • Complete - Combine all parts into final file and return the file metadata

We’ll walk through the following POST and PUT endpoints on the src/pages/api/multipart-upload.ts file to handle these operations.

1

Create the POST endpoint

First, let’s look at the POST endpoint that handles the creation of a new multipart upload session, as well as the completion once all parts are uploaded.

2

Create the PUT endpoint

Next, observe how the PUT endpoint handles the uploading of individual file parts.

Create the browser logic

The browser handles the chunking of the file and the uploading of the parts to the server. To do this, the client-side logic will need to:

  • Initiate - Get an uploadId from the server
  • Upload Parts - Send file chunks with the uploadId
  • Complete - Tell the server to combine all parts

The example repository already implements this logic, however below is a walk through of the code to understand how it works.

Test your multipart upload route

Now that your routes are setup, you can test your multipart upload route by uploading a large file.

1

Start your development server

Start your development server by running the following command:

$npm run dev

Your server should be running at http://localhost:4321/YOUR_BASE_PATH.

2

Upload a large file

Navigate to the file uploader page and upload a large file. You should see the file appear in the list of files.

Test your upload route
3

Deploy your app

Deploy your app to Webflow Cloud to start uploading large files. Commit and push your changes to your GitHub repository to start a deployment.

$git add .
>git commit -m "Add multipart upload endpoints"
>git push
4

Test your multipart upload route in your Webflow Cloud environment

Navigate to the file uploader page in your Webflow Cloud environment and upload a large file. You should see the file appear in the list of files.

FAQs

Since upload requests are made directly to the worker domain (not your Webflow Cloud domain), you need to handle CORS properly. Add these headers to your response:

Access-Control-Allow-Origin: <YOUR_WEBFLOW_CLOUD_DOMAIN>
Access-Control-Allow-Methods: POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type

If you’re looking to upload files from an authenticated user with session credentials, you’ll need to generate temporary upload URLs with embedded authentication tokens. Since CORS prevents passing session cookies directly, you can create a secure token that contains user information and embed it in the upload URL.

This approach involves:

  • Generating a temporary upload URL with an embedded authentication token
  • Validating the token on the upload endpoint
  • Using the worker domain for the actual file upload

For a complete implementation example, see the authentication upload example in the upload branch, which demonstrates how to handle authenticated file uploads with proper CORS and security.

Both the BASE_URL and ASSETS_PREFIX environment variables are automatically set by Webflow Cloud to help with routing logic in your app. You can access these variables as you would any other environment variable in your app.

  • BASE_URL is automatically set to the mount path of your environment (for example, /app). This is useful for setting up redirects and other routing logic in your app.
  • ASSETS_PREFIX is set to the domain of the Worker your app is deployed to (for example, https://YOUR_ENV_HASH.wf-app-prod.cosmic.webflow.services). This link is essential for uploading large files to your bucket, and serving files directly from your app. Because this link will always be a different domain than your app’s domain, you’ll need to handle CORS requests for the upload route.

Learn more about built in environment variables in Webflow Cloud.

No, presigned URLs require credentials that aren’t available in Webflow Cloud’s secure environment. Instead, use the multipart upload endpoints to upload files through your app’s API routes.

No, public buckets aren’t supported in Webflow Cloud. All bucket access must go through your app’s API routes, which gives you control over access permissions and allows you to implement proper authentication and authorization.

Likely the file being uploaded is hitting current Webflow Cloud request limits. You should upload these larger files through the multipart upload strategy.