I am very confused with how the pathing is supposed to work in my project. I have two folders in my main root folder – by root I mean the one I have open in VS Code which is called backend
– views
folder and public
folder.
I have file whose path is views/includes/head.ejs
. And in this file I want to link a stylesheet whose path is public/styles/shared.css
.
For Clarification thus far:
backend
|
|
|---public
| |
| |
| |---styles
| | |
| | |
| | |---"shared.css"
| | |
| | |
|---views
| |
| |
| |---includes
| | |
| | |
| | |---"head.ejs"
| | |
| | |
|---"app.js"
This works just fine <link rel="stylesheet" href="/styles/shared.css" />
.
Removing the forward slash at the beginning also works <link rel="stylesheet" href="styles/shared.css" />
which I don’t really understand. Isn’t this considered a relative path? How can my head.ejs
file see the styles
folder at all?
However this does not work <link rel="stylesheet" href="/public/styles/shared.css" />
and neither does this <link rel="stylesheet" href="public/styles/shared.css" />
.
But where it gets really confusing is when I try to access a parent folder like by using ../
.
This works <link rel="stylesheet" href="../../styles/shared.css" />
.
But this does not <link rel="stylesheet" href="../../public/styles/shared.css" />
?
I am running this code on a local node.js
server and these link requests are handled with use.express.static("public")
.
Can someone please tell me why it is behaving this way? Thank you.
2
Answers
The behavior you’re observing is due to how URL paths are resolved in web development, specifically with regard to static assets like stylesheets and how Express serves these assets.
Root Directory (Absolute Path) vs. Relative Paths:
When you start a path with a forward slash (/), it refers to the root directory of your project. In your case, this would be the backend directory.
A path without a forward slash is considered relative to the current directory of the file that references it.
Serving Static Files:
You mentioned that you’re using express.static("public"). This middleware serves static files from the public directory. When you request a file, Express starts looking for it in the public directory by default.
Read more here.
Now, let’s address your specific cases:
1-
<link rel="stylesheet" href="/styles/shared.css">
This path starts with a forward slash, making it an absolute path. When the browser encounters this, it looks for the "styles" folder at the root of your web server’s domain. In your case, this is working because Express is configured to serve static assets from the "public" folder, so it successfully finds "shared.css" within that folder.
2-
<link rel="stylesheet" href="styles/shared.css">
This path is relative to the current URL. When the browser is on a page like "/views/includes/head.ejs", it interprets this path as "/views/includes/styles/shared.css". Since this path doesn’t exist, it doesn’t work as expected. However, browsers often have built-in behavior to try and guess the correct path when a relative path doesn’t exist, which is why it might seem to work in some cases.
3-
<link rel="stylesheet" href="/public/styles/shared.css">
This absolute path is trying to access the "public" folder directly from the root of your web server’s domain, and it doesn’t match your Express configuration. Therefore, it doesn’t work as expected.
4-
<link rel="stylesheet" href="public/styles/shared.css">
Similar to #2, this relative path is resolved from the current URL. It tries to find "public/styles/shared.css" relative to your current URL, which doesn’t exist in your project structure.
5-
<link rel="stylesheet" href="../../styles/shared.css">
This relative path goes up two directory levels from "/views/includes/head.ejs" and then tries to access "styles/shared.css". This works because it correctly navigates to the "public" folder, where Express serves your static assets.
6-
<link rel="stylesheet" href="../../public/styles/shared.css">
This path goes up two directory levels from "/views/includes/head.ejs" and then tries to access "public/styles/shared.css", which doesn’t match your server configuration, so it doesn’t work.
tl;dr
the correct way to reference static assets in your Express.js project is to use absolute paths from the root, like , or relative paths that correctly navigate to the desired asset. The behavior might seem inconsistent in some cases due to how the browser interprets paths, but it’s essential to follow the correct conventions to ensure your project works as expected.
Given a URL with an absolute path (one starting with a
/
), the browser will:If the base URL is
https://example.com/
then that gives you:https://example.com/
https://example.com
https://example.com/styles/shared.css
Given a relative path, the browser will
/
in the current path and everything after itIf the base URL is
https://example.com/
then that gives you:https://example.com/
https://example.com/
https://example.com/styles/shared.css
You only get different URLs (with shared.css in them) if the base URL has multiple path segments in the first place (such as
https://example.com/foo/
, which would give youhttps://example.com/foo/styles/shared.css
for the relative path, but stillhttps://example.com/styles/shared.css
for the absolute one).Browsers deal in URLs. They neither no nor care how your HTTP server determines what to respond with for any given URL.
The browser asks for
https://example.com/
not forhttps://example.com/backend/views/includes/head.ejs
.That’s the same reason that the browser can’t ask for
../public
—..
would take it above/
in the URL path, andpublic
is never part of the URL. (At least, that’s what we can infer from your description of the behaviour. You haven’t shown us the Node.js code responsible for handling your URLs).