47

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
  • 3,141
  • 5
  • 21
  • 18

5 Answers5

39

Try

var templateContent = fs.readFileSync(path.join(__dirname, '../templates') + '/my-template.html', 'utf8');
jwchang
  • 10,584
  • 15
  • 58
  • 89
  • 7
    Isn'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/'? – user1438940 Oct 24 '12 at 15:10
  • @user1438940 I thought you executes the file reading code in `/server.js`. Try "../templates/my-template.html" – jwchang Oct 24 '12 at 15:12
  • 1
    no, 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 – user1438940 Oct 24 '12 at 16:47
  • @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. – jwchang Oct 25 '12 at 00:57
  • @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. – gregtzar Oct 25 '12 at 01:10
  • 1
    @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 Oct 25 '12 at 15:07
  • So 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) – Adrian H Aug 03 '16 at 16:05
34

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().

gregtzar
  • 2,458
  • 3
  • 26
  • 31
  • 1
    So, 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` so `process.cwd` returns `/`. – user1438940 Oct 25 '12 at 15:12
  • 3
    For 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 Sep 21 '16 at 21:35
  • `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 call `index.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`. – Tigran Mar 19 '20 at 11:53
20

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.

Community
  • 1
  • 1
deimosaffair
  • 333
  • 2
  • 4
  • 2
    I 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 to `path.join(__dirname)` which will work as long as the project files don't shift around. – Ninjaxor Aug 03 '15 at 20:26
  • 3
    For 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 Sep 21 '16 at 21:35
6

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 content1 = fs.readFileSync(relativePath('./file.xyz'), 'utf8') // same dir
const content2 = fs.readFileSync(relativePath('../file.xyz'), 'utf8') // parent dir
David
  • 513
  • 7
  • 14
0

We can use path madule to access the current path

const dirname = __dirname;
const path = require('path');


path.resolve(dirname, 'file.txt')

where

dirname  - is give us present working directory path name
file.txt - file name required to access
KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133