Proper way to reference files relative to application root in Node.JS
Solution 1
Try
var templateContent = fs.readFileSync(path.join(__dirname, '../templates') + '/my-template.html', 'utf8');
Solution 2
To get an absolute filesystem path to the directory where the node process is running, you can use process.cwd()
. So assuming you are running /server.js as a process which implements /services/template-reading-service.js as a module, then you can do the following from /service/template-reading-service.js:
var appRoot = process.cwd(),
templateContent = fs.readFileSync(appRoot + '/templates/my-template.html', 'utf8');
If that doesn't work then you may be running /service/template-reading-service.js as a separate process, in which case you will need to have whatever launches that process pass it the path you want to treat as the primary application root. For example, if /server.js launches /service/template-reading-service.js as a separate process then /server.js should pass it its own process.cwd().
Solution 3
Accepted answer is wrong. Hardcoding path.join(__dirname, '../templates')
will do exactly what is not wanted, making the service-XXX.js
file break the main app if it moves to a sub location (as the given example services/template
).
Using process.cwd()
will return the root path for the file that initiated the running process (so, as example a /Myuser/myproject/server.js
returns /Myuser/myproject/
).
This is a duplicate of question Determine project root from a running node.js application.
On that question, the __dirname
answer got the proper whipping it deserves.
Beware of the green mark, passers-by.
Solution 4
For ES modules, __dirname
is not available, so read this answer and use:
import { resolve, dirname, join } from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'
const relativePath = a => join(dirname(fileURLToPath(import.meta.url)), a)
const pathToFileInSameDirectory = relativePath('./file.xyz')
const pathToFileInParentDirectory = relativePath('../file.xyz')
const content1 = fs.readFileSync(pathToFileInSameDirectory, 'utf8')
const content2 = fs.readFileSync(pathToFileInParentDirectory, 'utf8')
user1438940
Updated on July 09, 2022Comments
-
user1438940 6 months
I have a Node.JS application running on Linux at AWS EC2 that uses the fs module to read in HTML template files. Here is the current structure of the application:
/server.js /templates/my-template.html /services/template-reading-service.js
The HTML templates will always be in that location, however, the template-reading-service may move around to different locations (deeper subdirectories, etc.) From within the template-reading-service I use fs.readFileSync() to load the file, like so:
var templateContent = fs.readFileSync('./templates/my-template.html', 'utf8');
This throws the following error:
Error: ENOENT, no such file or directory './templates/my-template.html'
I'm assuming that is because the path './' is resolving to the '/services/' directory and not the application root. I've also tried changing the path to '../templates/my-template.html' and that worked, but it seems brittle because I imagine that is just resolving relative to 'up one directory'. If I move the template-reading-service to a deeper subdirectory, that path will break.
So, what is the proper way to reference files relative to the root of the application?
-
user1438940 about 10 yearsIsn't __dirname actually the path to where the current script/module is? So in my example, when executing from within 'template-reading-service.js' wouldn't __dirname resolve to '/services/'?
-
jwchang about 10 years@user1438940 I thought you executes the file reading code in
/server.js
. Try "../templates/my-template.html" -
user1438940 about 10 yearsno, the code executing the fs.getFileSync is in the "template-reading-service.js". I don't want to use "../"; that's the entire point of my question. If I use "../" and then later I move "template-reading-service.js" from the "/services/" directory to "/services/templating/" then all my code breaks. Or, if I want to have the path to the template directory as a setting in a global config, which would then be used by 20 different other services, all located at different places in the directory structure, then "../" would not work from everywhere
-
jwchang about 10 years@user1438940 process.cwd() returns the absolute path of "js" file executed. Therefore you can run a js file in the root directory of the project directory and attach the rest at the end.
-
gregtzar about 10 years@InspiredJW process.cwd() returns the path of the parent directory of the js file running as the node process, not the js file it is executed in.
-
user1438940 about 10 years@InspiredJW it looks like you edited out your __dirname advice, but I ended up using it as my solution. In a global config, I used the following, which still seems pretty crappy to me....
templates: { directoryPath: path.join(__dirname, '../templates/') }
-
user1438940 about 10 yearsSo, I thought this might work for me, but it doesn't work in all of my environments. In my production environment, I'm using
forever
soprocess.cwd
returns/
. -
Ninjaxor over 7 yearsI had a horrible time using the app-root-path package. There were two ways to start my app, node lib/my_app.js or bin/my_app.js.
path.join(__dirname)
I spent lots of time and code patching app-root-path to work across platforms, ultimately I switched topath.join(__dirname)
which will work as long as the project files don't shift around. -
Adrian H over 6 yearsSo for anybody else that was trying to access the file in a relative way, like you do with require, you can't, you need the FULL_PATH (how you find it is a subjective thing)
-
TKoL over 6 yearsFor any future people looking at these answers: process.cwd is not necessarily the answer you're looking for. On windows, for example, if you run a node process from a .bat file, process.cwd() returns the path to the .bat file, not to the root of your node project. I believe similar rules apply to Linux and Mac.
-
TKoL over 6 yearsFor any future people looking at these answers: process.cwd is not necessarily the answer you're looking for. On windows, for example, if you run a node process from a .bat file, process.cwd() returns the path to the .bat file, not to the root of your node project. I believe similar rules apply to Linux and Mac.
-
Tigran almost 3 years
process.cwd()
returns the path of the directory where the entry script was called from, not the directory where the files is located. So, if you callindex.js
from/var/www/project
,process.cwd()
will be '/var/www/project', but if you call the same script from/var/www
it will be/var/www
.