
Yes, even on self-hosted setups like Railway
So this came up again today while I was wrapping up a small feature for the Smart Page Analyzer workflow I’m building for a client with n8n + OpenAI.
A while back, I needed to use cheerio
inside an n8n Function node to scrape and clean content from a blog post. The default setup obviously didn’t support it, because n8n doesn’t let you use external packages in function/code nodes out of the box.
Back then, I figured out how to get it working on a self-hosted n8n setup (mine’s running on Railway now). I did that again today and figured I’d document the process properly this time, in case someone’s searching for this and wants a straight answer that actually works.
Why You’d Even Want This
n8n’s built-in Function nodes are great — but kind of limited if you’re trying to do anything more complex like HTML parsing, date formatting, or HTTP chaining inside code.
That’s where external npm packages like:
cheerio
(for parsing HTML)moment
ordayjs
(for date/time)axios
(for extra HTTP control)lodash
(for data cleanup)
…become super useful.
But without adding them manually, you’ll get the classic:
Error: The expression evaluated to a falsy value: a.ok(nodeExists)
Or worse, a full crash because the module isn’t available in your container.
Here’s How I Installed Cheerio for n8n (Clean & Repeatable)
I’m running self-hosted n8n on Railway using Docker
This won’t work on n8n Cloud, but if you’re hosting it yourself — this works reliably.
Step 1: Enable external packages in n8n
In your Railway environment variables, add:
NODE_FUNCTION_ALLOW_EXTERNAL=cheerio
This tells n8n “Hey, I’m allowing this package to be used inside Function nodes.”
You can also comma-separate multiple ones:
NODE_FUNCTION_ALLOW_EXTERNAL=cheerio,moment,axios
Step 2: Modify your Dockerfile
If you deployed n8n using Railway’s template, it doesn’t expose the Dockerfile — so I switched to a custom GitHub repo with this Dockerfile
:
FROM n8nio/n8n
# Install external modules
RUN npm install cheerio
You can add any other packages you need here.
Step 3: Deploy from GitHub → Railway
- Push your custom
Dockerfile
to a GitHub repo - Create a new Railway project → Link GitHub
- Add the
NODE_FUNCTION_ALLOW_EXTERNAL
env var again - Done – Railway will build your custom image
Step 4: Use the Package in n8n
Once deployed, open your n8n instance and use cheerio
like this in a Function node:
const cheerio = require('cheerio');
const $ = cheerio.load($input.first().json.data);
const text = $('article').text(); // Or any tag you want
return [
{
json: {
cleanText: text
}
}
];
It works perfectly and doesn’t require any weird workarounds. This is exactly what I used in my Smart Page Analyzer client workflow.
👇 Here’s the Workflow Example
You can download the JSON here and import it into your n8n instance. Change the variables in the workflow.
It does the following:
- Pulls the latest post from your blog’s RSS feed
- Fetches the HTML
- Uses
cheerio
to extract clean article text - Sends it to OpenAI for SEO and structure analysis
- Pushes the output to Slack
You can modify step 5 to store it in Notion or Google Docs easily.
Quick Tip: Testing Locally First
If you’re running n8n locally with Docker Compose, you can build it with cheerio
like this:
FROM n8nio/n8n
RUN npm install cheerio
Run to build the custom image:
docker build -t n8n-custom .
Run to the container from the image we just created
docker run -it --name n8n-custom -p 5678:5678 --env-file .env -v "$(pwd)/n8n_data:/home/node/.n8n" n8n-custom
Works great for local debugging before pushing to production.
Final Thoughts
I’ve had to do this more than once now and with a lot of things going on, its hard to remember everything, I’m glad it’s finally documented to quickly find the steps.
If you’re using n8n as more than a simple Zapier clone, especially for dev-heavy stuff – being able to drop in your favorite npm packages can save you a lot of time.
If this helped or you want to see more of these behind-the-scenes posts, let me know. I’ll share more of the workflows I’ve built that go beyond just “connect this to that.”