How to Run EJS CLI on a Directory Recursively?

Abstract: Resolve the EJS CLI limitation of processing only single files by using a shell loop to recursively compile all templates in a directory.

Created: 2026-08-30 by

Running the EJS CLI on an entire directory recursively requires a shell loop because the tool processes single files. You can use find to locate all template files and pipe them into ejs. This approach ensures every file in subdirectories is processed without manual intervention.

Understanding the Limitation

The ejs command-line interface is designed to compile a single input file into a single output file. It does not have a built-in flag like --recursive or -r to traverse directories automatically. When you attempt to pass a directory path directly to ejs, it typically fails with an error indicating that the input must be a file. This limitation exists because the CLI expects a clear one-to-one mapping between source templates and destination HTML files, handling local variables and partials for that specific context. Attempting to run npx ejs ./src/views will result in an immediate failure. The tool cannot infer how to name the output files when multiple inputs are involved. Therefore, the solution relies on external shell commands to iterate through the directory structure and invoke the EJS compiler for each individual file found.

The Shell Loop Solution

The most robust method involves using the find utility combined with a while loop. This technique works across Linux, macOS, and Windows environments using Git Bash or WSL. The process identifies all files ending in .ejs and processes them sequentially. First, ensure your project structure has a source directory containing templates and a destination directory for the compiled output. For example, let templates be the source and dist be the target. Here is the standard command sequence:
find ./templates -name "*.ejs" | while read -r filePath; do
  outPath="${filePath%.ejs}.html"
  mkdir -p "$(dirname "$outPath")"
  npx ejs "$filePath" -o "$outPath"
done
This script performs several critical steps. The find command searches recursively for any file with the .ejs extension. The while read loop processes each line of output individually. Inside the loop, we calculate the output path by replacing the .ejs extension with .html. The mkdir -p command ensures that the directory structure for the output file exists before attempting to write to it. Finally, npx ejs compiles the specific file to the calculated output location. If you encounter issues with spaces in filenames, this method handles them correctly because read -r preserves the string integrity. Avoid using xargs for this task unless you carefully handle quoting, as xargs can break on filenames containing special characters if not configured properly.

Handling Variables and Data

When running EJS in a batch mode via a loop, you may need to pass data to the templates. The EJS CLI accepts data via -e (local variable) or -i (input JSON file). If all templates share the same global data, you can pass a JSON file to every iteration.
find ./templates -name "*.ejs" | while read -r filePath; do
  outPath="${filePath%.ejs}.html"
  mkdir -p "$(dirname "$outPath")"
  npx ejs "$filePath" -i data.json -o "$outPath"
done
This approach is efficient if your site configuration or user data remains constant across all generated pages. However, if different templates require different data contexts, you must modify the loop logic to determine which data file corresponds to which template. This might involve naming conventions, such as storing data.json next to the corresponding .ejs file, and reading it dynamically within the loop. For dynamic per-file data, you can check for the existence of a sibling JSON file:
find ./templates -name "*.ejs" | while read -r filePath; do
  outPath="${filePath%.ejs}.html"
  dataFile="${filePath%.ejs}.json"
  mkdir -p "$(dirname "$outPath")"
  
  if [ -f "$dataFile" ]; then
    npx ejs "$filePath" -i "$dataFile" -o "$outPath"
  else
    npx ejs "$filePath" -o "$outPath"
  fi
done
This conditional logic ensures that only templates with associated data files receive extra variables, preventing errors from missing data references in simple static pages.

Alternative Approaches

While the shell loop is lightweight and requires no additional dependencies, some developers prefer dedicated build tools. Tools like Gulp, Grunt, or Webpack have plugins specifically designed for EJS processing. These tools offer more advanced features such as watching for changes, minifying output, and managing complex asset pipelines. For instance, a Gulp setup can watch the templates directory and automatically recompile changed files. This is superior for development workflows where frequent regeneration is necessary. However, for simple deployment scripts or CI/CD pipelines, the shell-based approach remains preferable due to its simplicity and lack of runtime overhead. If you are working in a Node.js environment extensively, consider using the EJS programmatic API instead of the CLI. You can write a small Node script that uses fs and path modules to achieve the same recursive compilation with greater control over error handling and custom filters. For more information on navigating directory structures efficiently, see our guide on Finding Directories with Recursive Subdirectories that Don't Overlap in Linux Bash: A Printer-Friendly Guide. This resource provides deeper insights into using find for complex file operations.

Troubleshooting Common Errors

One common issue is permission denied errors when writing to the output directory. Ensure the user running the script has write access to the destination folder. Another frequent error occurs when the output path exceeds the maximum path length on certain operating systems. Keeping directory structures shallow helps mitigate this. If the script hangs or produces empty files, verify that the .ejs files are valid syntax. The EJS CLI will fail silently or produce empty output if there are unclosed tags or invalid expressions. Use npx ejs --help to review available flags and ensure you are passing arguments in the correct order. Additionally, if you are using Windows Command Prompt instead of PowerShell or Bash, the syntax for loops and variable expansion differs significantly. The provided examples assume a POSIX-compliant shell. For Windows CMD, you would need to use a for /f loop with different variable syntax, which is less readable and more prone to errors.

Frequently Asked Questions

Can I use npm scripts to run this recursively?

You can wrap the find command in a package.json script tag. Define a script like "build:views" that contains the full find loop. This allows you to trigger the build with npm run build:views. This keeps your build process portable and documented within the project.

Does this work with Nunjucks or Handlebars?

Yes, the shell loop pattern is agnostic to the templating engine. Replace npx ejs with npx nunjucks-precompile or your preferred CLI tool. Just ensure the output extension and argument flags match the specific tool's requirements.

How do I handle partials in recursive compilation?

Partials are resolved relative to the current file's directory during compilation. As long as your partial paths are relative or correctly registered in a global config passed via -i, the recursive loop will handle them correctly. Ensure partials do not depend on variables defined only in the parent template.

Is there a risk of infinite loops with symlinks?

Yes, if your directory structure contains symbolic links pointing back to parent directories, find might enter an infinite loop. Use the -not -type l option in your find command or rely on the default behavior of most modern find implementations which do not follow symlinks by default unless specified.

Why are my output files empty?

Empty outputs usually indicate a syntax error in the EJS template or a failed variable interpolation that resolves to nothing. Check the console output for warnings. Also, verify that the source file actually contains content after the EJS tags are evaluated.

Latest News

How to Display Output of xterm Command in Terminal Screen using Cron

Resolve the inability to display xterm output in a terminal screen from cron by redirecting logs or using wall instead of insecure X11 workarounds.

Read More
Expose Local Server on VPS Preserving Real Client IPs (OS Level)

Resolve VPS logging showing only gateway IPs by configuring reverse proxies to forward real client addresses via X-Forwarded-For headers.

Read More
How to Clear Recent Files History in Linux without Deleting Actual Files?

Clear recent files history in Linux by deleting ~/.local/share/recently-used.xbel without removing the actual files.

Read More
Best HDD Copy Strategy: Manually Syncing and Rewriting Scratch

Resolve data drift between two 4TB hard drives by using rsync with the --delete flag to manually sync and rewrite scratch data for an exact mirror.

Read More
Understanding Bash Prompt Abbreviations: An Overview

Resolve repetitive typing errors by creating and persisting Bash aliases in the .bashrc file for improved command-line efficiency.

Read More
Free Tools and Methods to Log Real-Time Performance Details in Task Manager

Log real-time CPU and memory metrics to CSV files using Windows Performance Monitor Data Collector Sets to troubleshoot system slowness.

Read More
Contact Qatar Airways Customer Service: Phone Number, Help Center, and More

Resolve urgent Qatar Airways reservation issues like flight changes and baggage claims using the US phone number +1801-855-5905 or online self-service tools.

Read More
Windows 11: Alt Codes Displaying Wrong Characters - Solutions

Resolve Windows 11 Alt codes showing wrong characters by verifying the US keyboard layout and enabling Num Lock.

Read More
Run Programs with Elevated Privileges: A Comprehensive Guide

Eliminates the need to type sudo for frequent administrative tasks by configuring .bashrc aliases or functions.

Read More
Dynamically Changing Dates in Excel Formulas Using Cells

Eliminate manual date updates in Excel by using cell references to create dynamic formulas that automatically adjust calculations when input dates change.

Read More
Granting Edit Access to a Specific Excel Sheet in an Office 365 User Email ID-Based Login

Excel Online lacks native sheet-level permissions, so users must split workbooks or use worksheet protection to isolate edit access for specific tabs.

Read More
Creating Network Load on Local Wi-Fi from One PC

Generate sustained Wi-Fi bandwidth load from a single PC using a VM SFTP server to test router stability and throughput.

Read More
Changing the Default Editor for Batch Files in Windows 11's File Explorer

Resolve the issue of batch files opening in Notepad by changing the default editor to a preferred application like VS Code.

Read More
Gain WiFi Connection Minutes Before Losing it by Changing MAC Address

Bypass MAC address filtering to restore WiFi connectivity temporarily when a device is blocked by network administrators.

Read More
Photos Folders Turned Black: Troubleshooting Picture Applications on Windows

Resolve black screens in Windows Photos by resetting the app, updating graphics drivers, and repairing system files.

Read More
Troubleshooting High CPU Temperature Values: A Step-by-Step Guide

Resolve high CPU temperatures and thermal throttling by monitoring with Speedfan, cleaning dust from cooling components, and replacing degraded thermal paste.

Read More
Make cURL establish TLS connection with CA unknown

Resolve cURL TLS connection failures with unknown or self-signed certificates by using the --insecure flag to bypass CA validation.

Read More
Troubleshooting Incorrect Network Metrics Values in Grafana, Prometheus, InfluxDB, and Telegraf

Fix incorrect network metrics in Grafana, Prometheus, InfluxDB, and Telegraf by verifying interface selection, resolving unit mismatches, and handling counter resets.

Read More
Start Another Terminal Window (cmd.exe) Windows Repair/Troubleshoot

Provides step-by-step instructions to access the Windows Command Prompt via bootable media for advanced system repair and troubleshooting.

Read More
Thinkpad P1 Gen 6: Sudden Thunderbolt 3 Dock USB-C Charging Stopped Working

Resolve sudden Thunderbolt 3 dock USB-C charging and internet failure on ThinkPad P1 Gen 6 by updating firmware, resetting the dock, and adjusting power settings.

Read More
ASUS Windows 11 Laptop: Internet Connection Issue with Hotspot

Resolve ASUS Windows 11 laptop spinning wheel issue when connecting to mobile hotspot by resetting network stack, disabling IPv6, and adjusting power settings.

Read More
Developing iOS Project with Firebase: Logging in and Sending Push Notifications

Integrates Firebase to enable secure user authentication and push notifications in iOS applications.

Read More
Troubleshooting Bash Script with Suspected Issues of Spaces, Dashes, Filenames and Quoting

Resolve Bash script failures caused by word splitting, globbing, and special characters in filenames by applying proper quoting techniques.

Read More
Populating OneDrive Folder for Local Backup without Affecting Remote Files

Prevent OneDrive from deleting remote files during Windows reinstallation by unlinking the account or using symbolic links to isolate local data.

Read More
Force First Frame as Keyframe Without Re-encoding: A Quick Solution

Resolve inaccurate seeking and playback glitches by re-encoding video to ensure the first frame is a valid keyframe.

Read More
Find Information in Database Using WSL (Ubuntu) on Windows-10

Resolve database connection issues from WSL Ubuntu on Windows 10 by configuring client tools and network access to query remote or local servers.

Read More
Configuring a New Router with Different Networks: One Family, One Guest

Resolve IP conflicts and isolate guest traffic by configuring a second router with a distinct subnet via its WAN port.

Read More
Quickly Open Multiple Stock Websites with a Single Command

Solve the problem of manually opening multiple stock research websites by creating a single command to launch them simultaneously on Windows, macOS, or Linux.

Read More
Improved Adobe Acrobat Search Experience: Access Advanced Search with Ease

Access advanced search filters like case sensitivity and regex in Adobe Acrobat by clicking More Options in the Find bar.

Read More
Port Forwarding VM via OpenVPN: A Comprehensive Guide

Configure OpenVPN server and iptables to forward specific ports from VPN clients to a virtual machine's internal IP address.

Read More
Understanding Partitions in the 1980s: A Look Back at MS-DOS and Master Boot Record

Explains how the Master Boot Record and partition table enabled MS-DOS to manage multiple disk volumes on a single physical drive.

Read More
Windows 10 Enterprise: Keyboard Not Detected in Managed Organization with Admin Privileges

Resolve Windows 10 Enterprise keyboard detection failures caused by Group Policy restrictions, driver corruption, or USB enumeration errors.

Read More
Can't Find x86_64 Versions of Applications on MacOS arm64 (M1)

Resolve missing x86_64 app issues on M1 Macs by installing Rosetta 2 and reinstalling apps as universal binaries.

Read More
How to Hide Installation Source for an Android App

Manage Android app installation source visibility by using USB transfers or file managers to reduce browser traces and isolate data via work profiles.

Read More
Connecting Momentus 4200.2 ST9808210A Hard Drive via USB Cable

Resolve inability to access Seagate Momentus 4200.2 ST9808210A hard drive by connecting it via USB using a compatible SATA-to-USB adapter and configuring the disk in Windows.

Read More