Skip to content

Update README #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 101 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,99 +1,116 @@
# Serving Assets Under a Custom Domain with Webflow Cloud
# Asset Routing with Webflow Cloud

[Webflow Cloud](https://webflow.com/cloud) enables you to deploy full-stack web applications directly under your Webflow-hosted domain. It can also be leveraged to serve assets from the same domain, which is especially useful for scenarios where assets must reside under the primary domain rather than Webflows default asset CDN path. Below is an overview of how to set this up, along with key considerations.
A Webflow Cloud example app demonstrating how to serve static assets directly under your Webflow-hosted domain. Built with Next.js, this app showcases asset routing techniques for scenarios where assets must reside under the primary domain rather than Webflow's default CDN path.

Example live paths:
## ✨ Features

- **Custom Asset Hosting**: Serve static assets directly under your Webflow domain
- **Flexible File Organization**: Support for nested folder structures in the public directory
- **API Route Implementation**: Custom Next.js API routes for secure file serving
- **Multiple File Type Support**: Handle images, documents, and other static assets

## 💡 Why Serve Assets Under Your Domain?

By default, Webflow hosts assets (e.g., images, documents, etc) via a standardized CDN URL (`cdn.prod.website-files.com/...`). However, certain use cases may require that assets be accessible directly under the custom domain (e.g., `https://yourdomain.com/assets/image.png`). Additionally, you can retain SEO benefits by serving assets all from the same domain rather than various external sources.

Webflow Cloud enables this with a structured approach using Next.js's `public` folder + API routing.

**Note:** _If you are still able to serve files directly from the public folder, this behavior may change in the future. Direct access to the public directory could be disabled, and using an API route will be required._

## 🛠️ Tech Stack

- **Webflow Cloud** - Infrastructure for hosting the webapp alongside a Webflow site
- **Next.js** - Webapp framework with API routing capabilities

## 📋 Prerequisites

Make sure you have the following before running the app locally:

- Install Node.js 18+ / npm / Git
- Webflow account (sign up for free) and site created
- Install the [Webflow CLI](https://www.npmjs.com/package/@webflow/webflow-cli)

## 🏗️ Getting Started

### 1. Fork and clone the repository

- Fork this repo into your own repositories so you have a copy of this project to work with
- Clone the repo down to your local machine
- `cd asset-routing-webflow-cloud`

### 2. Install and run locally

```bash
npm install
npm run dev
```

### 3. (Optional) Add your assets

Place any additional static assets in the `public` directory. You can organize them with the current subfolder structure:

- `/public/photo.png` → accessible at `/assets/photo.png`
- `/public/images/logo.png` → accessible at `/assets/images/logo.png`
- `/public/files/whitepaper.pdf` → accessible at `/assets/files/whitepaper.pdf`

**Note:** _`/assets` is the mount path for the Webflow Cloud app and is required. You will have the option to customize this mount path when creating the Webflow Cloud app. See [Webflow Cloud docs](https://developers.webflow.com/webflow-cloud/intro)._

### 4. Test asset serving

The development server will start and you can test asset access at:

- `http://localhost:3000/assets/[your-file-name]`

**Example localhost paths:**

- http://localhost:3000/assets/bird.jpg
- http://localhost:3000/assets/images/forest.jpg

**Example live paths:**

- https://wf-cloud-test-5650e8.webflow.io/assets/bird.jpg
- https://wf-cloud-test-5650e8.webflow.io/assets/images/forest.jpg

---
## 🚀 Deploy Webflow Cloud app

## Why Serve Assets Under Your Domain?
Once everything locally works OK, it's time to build and deploy the Webflow Cloud app to your Webflow site at the mounted path.

By default, Webflow hosts assets (e.g., images, documents, etc) via a standardized CDN URL (`cdn.prod.website-files.com/...`). However, certain use cases may require that assets be accessible directly under the custom domain (e.g., `https://yourdomain.com/assets/image.png`).
First, push up any code changes made to the project to the forked remote GitHub repo.

Webflow Cloud enables this with a structured approach using Next.js’s/Astro's `public` folder + API routing.
### Create Webflow Cloud app

**Note:** _If you are still able to serve files directly from the public folder, this behavior may change in the future. Direct access to the public directory could be disabled, and using an API route will be required._
> For more detailed guidance on creating a Webflow Cloud app, see [docs here](https://developers.webflow.com/webflow-cloud/intro) for a step-by-step.

---
In your Webflow site settings, navigate to the **Webflow Cloud** tab, click "Install GitHub App", and follow the prompts so Webflow can access your forked repo.

## Implementation Overview
Back in the Webflow Cloud page, click the "Create New Project" button and follow the prompts accordingly to add your project name, and the location of your GitHub repo.

### 1. Place Assets in the `public` Folder in Next JS/Astro
When you are prompted to create an **Environment**:

Add your static assets (images, documents, etc.) into the `public` directory of your Next.js project. You can organize them with subfolders or have them at the root like:
1. **Branch** - Select the GitHub branch you're working from (usually `main`)
2. **Mount Path** - Enter `/assets`

- `/public/photo.png`
- `/public/images/logo.png`
- `/public/files/whitepaper.pdf`
After the project is created, click "Publish" to re-publish your Webflow site. Once publishing completes, open your Webflow Cloud project, navigate into the **Environments**, then select the `main` branch name to view **Deployments**.

This structure allows access via routes like:
### Deploy the app

- `/assets/photo.png`
- `/assets/images/logo.png`
- `/assets/files/whitepaper.pdf`
Click the "Deploy latest commit" button to build and deploy the latest app from your repo.

**Note:** _`/assets` is the mount path for the Webflow Cloud app and is required. You will have the option to customize this mount path when creating the Webflow Cloud app. See [Webflow Cloud docs](https://developers.webflow.com/webflow-cloud/intro)._
After a few minutes, you can click the "Environment URL", which should be where the app is deployed to on your site (i.e. `https://{your-site-here}.webflow.io/assets/bird.jpg`).

### 2. Create an API Route to Serve Files
If you can access your assets at the expected URLs, congrats! You've deployed your first Webflow Cloud asset routing app 🎉

To serve files from the `public` folder, implement a custom API route like this:
If you make additional changes to your project, simply push them up to your repo on `main`, and Webflow will automatically kick off a new deployment with your changes. Also, if your deployment build fails for any reason, check the "Deployment History" for more logs.

```js
// route.js

// Import necessary Next.js server components and utilities
import { NextRequest, NextResponse } from "next/server";
// Import path module for handling file paths
import path from "path";
// Import file system promises API for async file operations
import { promises as fs } from "fs";
// Import mime-types for determining content type of files
import mime from "mime-types";

// Define GET handler for serving static assets
export async function GET(request: NextRequest) {
// Parse the request URL to extract the path
const url = new URL(request.url);
// Remove '/assets/' prefix and split remaining path into segments
const slug = url.pathname.replace(/^\/assets\//, "").split("/");

// Construct the full file path by joining current working directory, 'public' folder, and slug segments
const filePath = path.join(process.cwd(), "public", ...slug);

try {
// Read the file as a buffer
const fileBuffer = await fs.readFile(filePath);
// Determine the content type based on file extension, fallback to octet-stream
const contentType = mime.lookup(filePath) || "application/octet-stream";

// Return the file with appropriate headers
return new NextResponse(fileBuffer, {
status: 200,
headers: {
"Content-Type": contentType,
},
});
} catch (err: any) {
// Handle file not found or other errors
return new NextResponse(
JSON.stringify({
error: "File was not found",
}),
{
status: 404,
headers: { "Content-Type": "application/json" },
}
);
}
}
```
## 🔧 Implementation Details

### API Route for File Serving

To serve files from the `public` folder, see the `[...slug]/route.ts` [file here](src/app/[...slug]/route.ts).

**Note:** _For security purposes, it's not possible to set your own cache control headers (they will be overridden)._

## Using Hosted Assets in the Webflow Designer
## 🎨 Using Hosted Assets in the Webflow Designer

To use these custom-hosted assets inside the Webflow Designer, use the [Custom Element](https://help.webflow.com/hc/en-us/articles/33961250668691-Custom-element).

Expand All @@ -103,9 +120,9 @@ For example, use the `<img>` tag and reference the hosted asset with the src att

**Note:** _Use the loading attribute for performance optimization. For example, loading="lazy" for below-the-fold images and loading="eager" for above-the-fold content like hero banners._

## Limitations of This Approach
## ⚠️ Limitations of This Approach

While this method provides flexibility, do not rely on it as your primary asset management strategy. Limitations include:
While this strategy provides flexibility, we do not recommend relying on it as your primary asset management strategy. Limitations include:

- No responsive variants
- No native compression options i.e., convert JPG/PNG to WEBP/AVIF
Expand All @@ -114,7 +131,7 @@ While this method provides flexibility, do not rely on it as your primary asset

For most use cases, Webflow's built-in [Asset Panel](https://help.webflow.com/hc/en-us/articles/33961269934227-Assets-panel) should be the preferred choice.

## Optional: Redirect Unused Paths
## 🔄 Optional: Redirect Unused Paths

If your Webflow Cloud project is only used to serve assets, consider redirecting the root or other unused paths back to the main Webflow site and prevent users from landing on empty or incorrect pages.

Expand All @@ -127,7 +144,7 @@ This can be done by defining a page like...
import { redirect } from "next/navigation";

export default function AssetsRootRedirect() {
redirect("https://wf-cloud-test-5650e8.webflow.io");
redirect("https://your-webflow-site.webflow.io");
}
```

Expand All @@ -151,3 +168,11 @@ module.exports = {
},
};
```

## 🤝 Contributing

Feel free to submit issues and pull requests!

## 📄 License

This project is MIT licensed.