A Node.js service that provides secure code execution for JavaScript functions with dependency management and caching.
Run code in n8n with NPM dependencies
CodeHarbor includes a built-in web dashboard for monitoring, analyzing, and executing jobs directly from the browser.
Dashboard features:
- Job History — Browse, search, and filter all executions with status, timing, and cache info
- Code Editor — Write and execute JavaScript code with syntax highlighting directly from the browser
- Binary Output — Preview images, play audio/video, and download files generated by your code
- Cache Analysis — Monitor dependency cache usage, sizes, and installed packages
- Interactive Examples — Try ready-to-run examples (QR codes, PDFs, memes) with one click
- API Documentation — Embedded Swagger UI for exploring and testing the REST API
- System Info — View Node.js version, pnpm version, and CodeHarbor version at a glance
Access the dashboard at http://localhost:3000/dashboard after starting the server. Login with your SECRET_KEY.
The easiest way to run CodeHarbor-Executor in production is using the official Docker image available on Docker Hub.
# Pull the latest image
docker pull brorlandi/codeharbor-executor:latest
# Run the container
docker run -d \
--name codeharbor-executor \
-p 3000:3000 \
-e SECRET_KEY="your-super-secret-key" \
-e DEFAULT_TIMEOUT=60000 \
-e CACHE_SIZE_LIMIT="1GB" \
-v codeharbor_data:/home/codeharbor/app/data \
--restart unless-stopped \
brorlandi/codeharbor-executor:latestExplanation:
-d: Run the container in detached mode (in the background).--name codeharbor-executor: Assign a name to the container.-p 3000:3000: Map port 3000 on the host to port 3000 in the container.-e SECRET_KEY=...: Required: Set a secure secret key for authentication.-e DEFAULT_TIMEOUT=...: (Optional) Set the default execution timeout in milliseconds.-e CACHE_SIZE_LIMIT=...: (Optional) Set the maximum cache size (e.g., "500MB", "2GB").-e DEPENDENCY_VERSION_STRATEGY=...: (Optional) Set the dependency version strategy ("update" or "pinned").-v codeharbor_data:...: Recommended: Mount a Docker volume to persist all data (database, cache, and executions).--restart unless-stopped: Automatically restart the container unless manually stopped.
Adjust the environment variables (-e) as needed based on the Configuration section.
Alternatively, you can use the provided docker-compose.yml file to manage the service configuration and deployment more easily:
- Create an environment file: Copy the
.env.exampleto.envand configure yourSECRET_KEYand other settings within the.envfile.cp .env.example .env # Edit .env file with your settings - Run Docker Compose:
docker-compose up -d
This command will build (if necessary) and start the service based on the settings in docker-compose.yml and your .env file. The docker-compose.yml file already includes the recommended volume mounts for cache and data.
If you want to contribute to the project or run it locally for testing purposes, follow these steps:
# Clone the repository
git clone https://github.com/BrOrlandi/CodeHarbor-Executor.git
# Navigate to the project directory
cd CodeHarbor-Executor
# Install dependencies
pnpm install
# Build the dashboard frontend
cd dashboard && pnpm install && pnpm build && cd ..
# Create a .env file (optional, copy from example)
cp .env.example .env
# Start the server
pnpm start
# Or start in development mode with auto-reload
pnpm devThe service uses environment variables for configuration. When running with Docker, pass these using the -e flag. When running locally for development, you can create a .env file in the root directory.
# .env file content example
PORT=3000
SECRET_KEY=your-secret-key-here
DEFAULT_TIMEOUT=60000
CACHE_SIZE_LIMIT=1GB
DEPENDENCY_VERSION_STRATEGY=update
EXECUTIONS_DATA_PRUNE_MAX_COUNT=100
DASHBOARD_ENABLED=trueThe following environment variables can be used to configure the service:
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
The port on which the service will run |
SECRET_KEY |
(none) | Authentication token for API calls and dashboard login |
DEFAULT_TIMEOUT |
60000 |
Default execution timeout in milliseconds |
CACHE_SIZE_LIMIT |
1GB |
Maximum cache directory size (e.g., "500MB", "2GB") |
DEPENDENCY_VERSION_STRATEGY |
update |
How dependency versions are resolved (update or pinned) |
EXECUTIONS_DATA_PRUNE_MAX_COUNT |
100 |
Maximum number of execution directories and job history records to keep |
DASHBOARD_ENABLED |
true |
Enable or disable the web dashboard |
DATA_DIR |
./data |
Root directory for all persistent data (database, cache, executions) |
EXECUTION_DIR |
${DATA_DIR}/executions |
Directory where per-execution workspaces are stored |
CACHE_DIR |
${DATA_DIR}/cache |
Directory for dependency cache entries |
Dependency version strategies:
update: Always installs the latest version of dependencies. When the cache is updated, the previous version is removed.pinned: On the first installation, saves the exact installed versions. On subsequent installations, reuses the saved versions even if newer versions are available. New dependencies (without a saved version) still install as latest.
Endpoint: POST /execute
Authentication:
Authorization: Bearer YOUR_SECRET_KEY
(Required only if SECRET_KEY is configured)
Request Body:
{
"code": "module.exports = function(items) { console.log('Processing items:', items); return items.map(item => item * 2); }",
"items": [1, 2, 3, 4, 5],
"cacheKey": "workflow-123-node-456",
"options": {
"timeout": 30000,
"forceUpdate": false,
"debug": true
}
}Parameters:
code(required): JavaScript code that exports a functionitems: Input data to pass to the function (default: [])cacheKey(required): Unique identifier for dependency cachingoptions:timeout: Custom execution timeout in millisecondsforceUpdate: Force fresh installation of dependenciesdebug: When set to true, returns detailed debug information about the execution
Response:
{
"success": true,
"data": [2, 4, 6, 8, 10],
"jobId": "job-1710123456789-abc12345",
"console": [
{
"type": "log",
"message": "Processing items: [1,2,3,4,5]",
"timestamp": "2023-06-25T14:30:45.123Z"
}
],
"debug": {
"server": {
"nodeVersion": "v22.22.1"
},
"cache": {
"usedCache": true,
"cacheKey": "workflow-123-node-456",
"currentCacheSize": 5242880,
"currentCacheSizeFormatted": "5 MB",
"totalCacheSize": 52428800,
"totalCacheSizeFormatted": "50 MB"
},
"execution": {
"startTime": "2025-03-10T14:30:45.123Z",
"installedDependencies": {
"lodash": "4.17.21"
},
"dependencyInstallTimeMs": 345.67,
"totalResponseTimeMs": 358.01
}
}
}Every execution is automatically recorded in the job history database and can be viewed in the dashboard.
Console Capture
All console output from the executed code is captured and returned in the console property of the response. Each log entry includes:
type: The type of console method used (log, info, warn, error, debug)message: The content of the log messagetimestamp: When the log was generated
curl -X POST http://localhost:3000/execute \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-secret-key-here" \
-d '{
"code": "module.exports = function(items) { console.log(\"Processing items\"); return items.map(item => item * 2); }",
"items": [1, 2, 3, 4, 5],
"cacheKey": "workflow-123-node-456",
"options": {
"debug": true
}
}'curl -X POST http://localhost:3000/execute \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-secret-key-here" \
-d '{
"code": "const _ = require('\''lodash'\''); module.exports = function(items) { console.log(_.map(items, String)); return _.map(items, item => item * 2); }",
"items": [1, 2, 3, 4, 5],
"cacheKey": "workflow-123-node-456"
}'When the dashboard is enabled, interactive API documentation is available via Swagger UI at http://localhost:3000/api/docs.
See Advanced Examples for more complex use cases including binary data processing, image generation, PDF creation, QR codes, audio conversion, and more.
You can also try these examples interactively in the Dashboard.
Endpoint: GET /health
Response:
{
"status": "ok",
"version": "2.1.0",
"auth": "enabled",
"defaultTimeout": "60000ms"
}Endpoint: GET /verify-auth
Authentication:
Authorization: Bearer YOUR_SECRET_KEY
(Required only if SECRET_KEY is configured)
Response:
{
"success": true,
"message": "Authentication successful",
"authenticated": true
}If authentication fails, the server will return a 401 Unauthorized response.
- Authentication via SECRET_KEY environment variable
- Code is executed in isolated environments using Node.js child processes
- Execution timeout prevents infinite loops and long-running processes
- Dependencies are automatically detected and installed from code
- Dependency caching improves performance and reduces npm requests
- Automatic cleanup of execution directories after code runs
- Native Node.js modules detection to prevent unnecessary installations
- Console output is captured and returned as structured data to prevent interference with the execution process
- Dashboard uses HTTP-only cookie authentication separate from the API Bearer token
When using Puppeteer in your code, always configure the launch method with the following parameters to ensure proper execution in the CodeHarbor environment:
const browser = await puppeteer.launch({
executablePath: '/usr/bin/chromium',
args: ['--no-sandbox', '--disable-setuid-sandbox'],
headless: true,
});Example function using Puppeteer:
const puppeteer = require('puppeteer');
module.exports = async function (urls) {
const browser = await puppeteer.launch({
executablePath: '/usr/bin/chromium',
args: ['--no-sandbox', '--disable-setuid-sandbox'],
headless: true,
});
try {
const page = await browser.newPage();
const results = [];
for (const url of urls) {
await page.goto(url, { waitUntil: 'networkidle2' });
const title = await page.title();
results.push({ url, title });
}
return results;
} finally {
await browser.close();
}
};- Code Execution: Run JavaScript code with dependencies in a secure environment
- Dependency Management: Automatically install and cache required packages
- Console Capture: All console output (log, info, warn, error, debug) is captured and returned in the response
- Execution Timeout: Prevent infinite loops and long-running processes
- Caching: Reuse installed dependencies to improve performance
- Smart Cache Verification: Automatically detects when new dependencies are required and updates the cache accordingly
- Debug Information: Optional detailed execution statistics and environment information
- Job History: SQLite-backed persistent history of all executions with search, filtering, and statistics
- Web Dashboard: Vue.js SPA for monitoring jobs, executing code, analyzing cache, and browsing documentation
- Binary Output Support: Handle and preview images, audio, video, and file outputs from executed code
- Swagger API Docs: Interactive API documentation available at
/api/docs
For n8n users, we recommend using the dedicated n8n-nodes-codeharbor custom node. This node provides a seamless integration between n8n workflows and the CodeHarbor-Executor service.
- Add the CodeHarbor node to your n8n workflow
- Configure the node with your JavaScript code and options
- The node sends your code and workflow data to the CodeHarbor-Executor service via its REST API
- CodeHarbor executes the code in a secure environment with the requested NPM dependencies
- The results are returned to the n8n node, which outputs them to the next node in your workflow
This integration allows you to execute custom JavaScript code with any NPM dependencies directly in your n8n workflows without installing packages on your n8n server.
Follow the installation instructions on the n8n-nodes-codeharbor repository to integrate CodeHarbor with your n8n instance.
To make it even easier to generate code for your CodeHarbor node, a specialized GPT Agent is available in ChatGPT:
This custom GPT is designed specifically to help you:
- Generate JavaScript code for your CodeHarbor node
- Handle complex data transformations
- Process binary data correctly
- Implement optimized solutions for n8n workflows
- Format code according to CodeHarbor's best practices
Simply describe what you want to achieve in your workflow, and the agent will generate ready-to-use code tailored for CodeHarbor.

