This quick tutorial shows how to use subdomains with Express.js. If you don’t know Express.js yet, check out some of the previous tutorials, like the introduction to Node.js/Express servers tutorial.
Create a simple Express.js app
Create a new project folder and create two files: package.json
and app.js
.
The package.json
file should look something like this:
{
"name": "@j127/express_subdomains",
"version": "0.1.0",
"description": "A simple example of using subdomains with Express.js",
"scripts": {
"start": "npx nodemon app.js",
"format": "prettier \"**/*.{js,css,html,json,ts}\" --write"
},
"author": "your name",
"license": "BSD-3-Clause"
}
The app.js
file should look like this to start:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("hello world");
});
const PORT = 3000;
app.listen(PORT, () => console.log(`server is running at 127.0.0.1:${PORT}`));
Install the dependencies
This will install the dependencies and save them:
$ npm install --save express vhost
$ npm install --save-dev nodemon prettier
Formatting your code
For this tutorial, I’ve added prettier
as a dependency to help people automatically keep their code neat. Put a file named .prettierrc
in your project with these contents:
{
"endOfLine": "lf",
"semi": true,
"singleQuote": false,
"tabWidth": 4,
"trailingComma": "es5"
}
Also create a file named .prettierignore
with these contents:
node_modules/
.git/
From this point on, you’ll be able to type one command to format all the code perfectly:
$ npm run format
Those files are in all of my sample repos, so if you’re wondering what they do, that’s basically it, except that my editor formats the code automatically.
Edit your hosts file
Next step: to view your server with temporary host names, you’ll need to set up your hosts file so that you can access your local server by some custom domain name.
I’m using Linux, and my hosts file is located at /etc/hosts
. If you’re using Mac or Windows, find your hosts file with these instructions.
You’ll probably need to use sudo
to edit the /etc/hosts
file. You can type something like this to edit it on Linux:
$ sudo nano /etc/hosts
Add lines for your local (made-up) domain name and subdomains that point to your local machine (127.0.0.1
) like this:
127.0.0.1 mysite.local
127.0.0.1 cats.mysite.local
127.0.0.1 dogs.mysite.local
If your server is running on port 3000, then you will be able to visit any of these to view your local development site:
mysite.local:3000
cats.mysite.local:3000
dogs.mysite.local:3000
The names above are arbitrary — you can use whatever names you want in development.
Check that it’s working
The app should now run if you start it like this:
$ npm start
Visit these URLs to check, and the content should be the same for all of them:
localhost:3000
mysite.local:3000
cats.mysite.local:3000
dogs.mysite.local:3000
Add subdomain routing
Here’s the app.js
file with working subdomains. It isn’t in the final form yet, but I kept it as simple as possible (in one file) for a first look. Read the comments and code to see what it does.
// Import the two dependencies
const express = require("express");
const vhost = require("vhost");
// Create an app for the top-level domain
const app = express();
// Create an app for each subdomain. You can call these whatever you want.
const cats = express();
const dogs = express();
// Set the domain based on whether it's in production or not. If the
// syntax doesn't look familiar, look up "ternary operator javascript"
// in a search engine or leave a comment below.
const domain =
process.NODE_ENV === "production" ? "example.com" : "mysite.local";
// Mount the extra apps on their subdomains.
app.use(vhost(`cats.${domain}`, cats));
app.use(vhost(`dogs.${domain}`, dogs));
// The routers will be moved to their own files in another step.
// a router for the root domain
app.get("/", (req, res) => {
res.send(`hello world`);
});
// a router for the cats subdomain
cats.get("/", (req, res) => {
res.send("here is the cats subdomain");
});
// a router for the dogs subdomain
dogs.get("/", (req, res) => {
res.send("here is the dogs subdomain");
});
// start the server
const PORT = 3000;
app.listen(PORT, () => console.log(`server is running at 127.0.0.1:${PORT}`));
Check the URLs to see the changes:
mysite.local:3000
cats.mysite.local:3000
dogs.mysite.local:3000
Larger Example
I wrote a quick, larger example and put it on Github. I wrote this tutorial and all the code in two hours, so it’s rough and there are better ways to do some of the things, but it at least shows how to begin splitting things up into their own files. Leave a comment below, or make a pull request if you have suggestions (as long as they don’t make the example too complex).
I recommend reading the files in this order:
-
package.json
– it lists dependencies -
app.js
– it sets everything up - the files in
routes
– these link the routes to controller functions - the files in
controllers
– these contain the functions that generate the pages and send responses - the files in
views
– these are the template files that get rendered by the controller functions
Other Resources
This video shows similar functionality coded from scratch. It’s in Portuguese, but the code is readable.