Serve local files using a flow

In some cases, you may want to serve local project files (e.g., CSS, JavaScript, images) directly from your Node-RED flow rather than using a static folder configuration. While the Serving Static Files approach works, it tightly couples your project to an absolute path, making it hard to relocate.

Using a flow to serve files from your project folder provides more flexibility and keeps the project self-contained.

A four-node workflow to serve local files. Nodes are described in the text below.

Prerequisites

Define an environment variable pointing to your project directory:

If using Node-RED Projects:

Copy
ENV_PROJECT_A = C:\ProgramData\Objectif Lune\OL Connect Automate\projects\project_a

If not using Projects (User Data Folder):

Copy
ENV_PROJECT_A = C:\ProgramData\Objectif Lune\OL Connect Automate\projects\project_a

Assume the static resources are stored under a subfolder called assets, e.g.:

Copy
assets/
├── styles.css
├── javascripts.js
└── logo.png

Note: While you could include assets in the environment variable path itself, keeping it separate allows for more modular and extensible setups.

Flow setup

Create the end point

Insert an http in node, configured to set the Method to GET and URL to:

Copy
/assets/:resource

This sets up a route where :resource is a path variable (e.g. styles.css). The requested filename will be available as msg.req.params.resource.

Load the file

Add a read file name and set the filename using a JSONata expression:

Copy
$env("ENV_PROJECT_A") & "\\assets\\" & msg.req.params.resource

This dynamically reads the requested file from the local assets folder.

Set the Content-Type header

The HTTP Content-Type header is used to indicate the original media type of a resource before any content encoding is applied. The Content-Type header informs the client about the media type of the returned data and is essential for browsers to interpret resources properly.

In our scenario we will set this dynamically based on the file extension of the requested file. Add a function node after the file read to assign the correct Content-Type header based on the file extension.

Copy
const resource = msg.req.params.resource; // the name of the requested file resource
const ext = resource.split('.').pop().toLowerCase(); // get the file extenion without the dot

const mimeTypes = {
    'css' : 'text/css',
    'js'  : 'application/javascript',
    'html': 'text/html',
    'json': 'application/json',
    'png' : 'image/png',
    'jpg' : 'image/jpeg',
    'jpeg': 'image/jpeg',
    'svg' : 'image/svg+xml'
};

msg.headers = {
    'Content-Type': mimeTypes[ext] || 'application/octet-stream' // fall back to octet-stream for unknown types
};

return msg;

Result

When you navigate to:

http://localhost:1880/assets/styles.css

OL Connect Automate:

  • Reads styles.css from the local assets folder (under ENV_PROJECT_A).

  • Serves it with the correct Content-Type header (text/css).

This makes your project more portable and avoids hardcoded file paths outside the flow logic.