Bootstrapping a Node App

In this tutorial, we will:

If you prefer video, scroll to the bottom. There’s a video there of me walking through the entire tutorial.

Some Definitions

[Note: you don’t need to worry much about differences between any of the above…]

Install Node

You can download an installer here. I won’t go into detail because the installation has always “just worked” for me, on Windows or Mac.

Once the installation is complete, do this from a command prompt (anywhere):

node -v

That command is running Node and asking it what version it is. If Node is installed, you should get something like this:

v20.10.0

(Your exact version might vary. It doesn’t matter.)

Bootstrap an App

Create an empty directory, named for your project. (The name doesn’t matter. I would avoid spaces because that can make some version control stuff hard…)

From a command prompt, enter the directory you just created, and do this:

npm init

The command prompt will ask you a bunch of questions – just keep hitting enter. Eventually it will exit, and it will have created a file in the directory called package.json.

That’s literally all this command does – create this one file. It’s just JSON. Open it, look through it. This is just where Node and npm store and retrieve data about the app.

There’s nothing magic about the file – you can write it by hand if you want (hint: you don’t).

If you want to skip all the questions and just take the defaults, do this:

npm init -y

You can delete the newly-created file and recreate it if you want. Again, there’s nothing magic about it, and creating it is all the init command does. (But after you’ve started doing stuff with your app, there will be more in this file, so don’t delete it then.)

Now create a folder called src. This is where you will put your code. This is not required, but it’s a convention. Most Node developers will expect your code to be in src.

Inside src, create a text file called app.js. This is the main executable file of your app. This is also not a required name, but it’s a loose convention. app.js is common, but you might see server.js or index.js – it doesn’t really matter, honestly, so long as you know what it is.

Inside that file, type this:

console.log("Hello World!")

Now, from the root directory (one up from src), do this from the command line:

node src/app.js

(Or, whatever you called your file, if you didn’t call it app.js)

You should see:

Hello World!

Congratulations. This is a running Node app.

It’s self-contained – there’s nothing “outside” of this directory. You can move it or copy it and run it from some other location. You can even zip it up and email it to someone if you want – so long as they have Node installed, they can run it too.

Importing Code

You can do whatever you want inside app.js, but eventually you’re going to want code from somewhere else.

Inside src, create a directory called lib (again, just a convention; call it whatever you want).

Inside that directory, create a file called greeting.js.

Inside that file, do this:

function greeting() {
    console.log("This is from your included code…");
}

export { greeting }

The first part of that is just a standard function. The last line is the important part – you have to explicitly specify everything you want available outside this file.

You can have a bunch of stuff in this file – you could have 1 million lines of code – but you have to specifically say what to want to be available outside of it when something else imports it. You might only export one little function call out of that million lines of code.

Now, go back to app.js and write this at the top of that file:

import { greeting } from './lib/greeting.js'

What we’re saying there is that we want whatever greeting is in the file located at ./lib/greeting.js. We don’t know what it is – it might be a class definition, a function, a variable, it doesn’t matter. We just want to use it inside app.js

A few notes:

Now that we’ve exported greeting from our library code, and imported it in our app code, we can use it. At the bottom of the app file, call the function:

greeting();

You should get output like this

Hello World!
This is from your included code…

So, we did two things:

  1. We exported greeting in our library file
  2. We imported greeting in our app file

Obviously, the names have to match. If I try to import greetMe, I’ll get this:

The requested module './lib/greeting.js' does
not provide an export named 'greetMe'

You can export multiple things at once. If you have another function in that file called otherGreeting, you can do this at the bottom:

export { greeting, otherGreeting }

Then, at the top of your app file:

import { greeting, otherGreeting } from './lib/greeting.js'

You can export as many things as you like, but a general rule (in programming, universally) is that you only export what code outside the file should see. Expose as little as possible.

Also, if you don’t feel like writing an explicit export statement at the bottom, you can do it directly in the function declaration:

export function greeting()

Finally, if you only want to export one thing from a file, you can specify that one thing as the “default export,” like this:

export default greeting

What benefit does this provide over specifically giving it a name? Well, this means you don’t have to know the name of what you’re exporting, which can be handy when using other people’s code. You’re basically just saying, “Give me the main thing this code does…”

One effect this has is that the code using it can call the import anything it likes. And this makes sense: since there’s only one export, you don’t really have to know what it’s called and can call it whatever you want.

import wtf from './lib/greeting.js'

(Note that there are no braces around wtf. Near as I can tell, this is how the engine knows if you want named exports or just want the default.)

Then you can use it as whatever you called it.

wtf()

Why we had to change package.json…

In a sidebar above, I had you add this to package.json:

"type": "module"

This is because JavaScript changed how code was included, and it needs to know how to parse the file.

This was the old syntax:

const greeting = require('./lib/greeting.js');

Again, this old. But, for whatever reason, the newer syntax requires the package.json change, and npm doesn’t add that by default.

I have no idea why. I assume this will change in the future, and you’ll have to modify package.json to use the old syntax, but who knows…

Installing Packages

Eventually, at some point, you’re gonna want to use someone else’s code. For this example, we’re going to install and use a package called Moment.js which is used to format and manipulate dates (default date handling in JavaScript is very bad).

To install a package, do this from anywhere in your app.

npm install moment

This will download the code for the package, and put in a directory called node_modules in the root of your application (so, one up from src). npm installs packages to the nearest directory it can find that contains a package.json file. So if you execute the install command in subdirectory, npm will keep looking “upward” until it finds the directory that contains package.json.

If you go into node_modules, you might find a bunch of stuff in addition to the package you installed. These are packages that package installed. These are called “transitive dependencies.” Sometimes, installing a single package will result in dozens of other packages being automatically installed because the package you want depends on them.

Once the package is installed, you import it pretty much just like we did previously.

import moment from 'moment'

The one difference here is that we’re not referring to a file, we’re referring to an installed package, so we don’t start with a dot (it’s not a file path, after all).

Also, moment has a default export, so we can call it whatever we want. In this case, we’re calling it moment, which looks a little weird because the package is also called moment. This is pretty common (we’ll do the same thing with Express below), but it always looks weird to me.

In your app file, do this:

console.log(moment().format())

moment exports a function. We’re calling that function, then calling format() on the output. This should give you output that looks something like this:

2025-02-09T20:44:29-06:00

So, other than the import syntax changes, using installed packaged code is just like using included code of your own.

If you look in the package.json, you’ll see that npm has modified it. It will have added something like this:

"dependencies": {
  "moment": "^2.30.1"
}

So, now the app “remembers” that it has moment installed and what version it is. Later, you can auto-upgrade or restore packages, because npm keeps track.

Package names sometimes will have @ signs in them. This is what those mean:

You can remove a package like this:

npm uninstall moment

Installing and Running Express

In most cases, you’re going to want to run a web server. Node can and does a bunch of command line scripting stuff, but to write a Node web app, you need a web server.

Express is the most common web server for Node. (There are probably others, but I couldn’t name one…)

Install it:

npm install express

Now, in your app file, add this:

import express from 'express'

const app = express()

app.get('/', (req, res) => {
    res.send('Hello World!')
})

app.listen(3000)

(Again, as with Moment, we’re using the package name for the name of the thing we’re importing, which just never looks right to me…)

We’re doing three things:

  1. Getting a variable called app from the express function that we imported
  2. Configuring a “route,” for the home page (just the forward slash). We’re supplying some code to send back a message
  3. Telling Express to listen on port 3000

Run this code like before, but you’ll see an important difference: the code does not finish. app.listen doesn’t… stop. It will just hold the code there, while it listens for requests.

Open a browser and go to http://localhost:3000/ and you should see:

Hello World!

To stop the script, press CTRL-C at your command line.

There’s a lot to Express that I won’t cover here, but I’ll finish by showing you how to map a variable route. Add this before the app.listen line:

app.get('/greet/:name', (req, res) => {
    res.send('Hello ' + req.params.name + '!')
})

(If you haven’t stopped the script from before, you’ll need to stop and restart it for these changes to work.)

This is mapping another route: /greet/[something]. The code is grabbing the [something] from the URL and using it in the message to the user.

Go to http://localhost:3000/greet/bob and you should see:

Hello bob!

…and there you go. You wrote a functional web app in JavaScript, running under Node, using Express.

Video

Here’s a 15-minute video of me doing everything in this tutorial, complete with mistakes.