Almost nobody writes a server from nothing. You use packages: small libraries other people wrote and published. npm is the tool that downloads them, and package.json is the file that lists what your project needs and how to run it. This lesson creates the server folder of the Job Tracker and sets up the two things every real project needs from day one: scripts to run it, and a safe way to keep settings out of the code.
package.json: the identity card of a project
npm init -y creates a package.json. The fields that matter are these.
- `"type": "module"` switches the project to modern ES modules, so you write
importandexportinstead ofrequire. The whole course uses this. - `scripts` are named commands.
npm run devruns thedevscript.startandtestare special: you can writenpm startandnpm testwithoutrun. - `dependencies` are packages your program needs while it runs. `devDependencies` are only for development, such as test or build tools.
- Version numbers like
^5.2.1mean “5.2.1 or any newer 5.x version”. The exact versions that were installed are recorded inpackage-lock.json, which you should commit: it makes everyone, including your server, install the same versions.
{
"name": "job-tracker-server",
"version": "1.0.0",
"private": true,
"type": "module",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "node --watch index.js"
},
"dependencies": {
"dotenv": "^17.3.1"
}
}
Installing and the node_modules folder
npm install express downloads Express and its own dependencies into node_modules/ and adds it to dependencies. npm install with no name installs everything listed in package.json, which is what you run after cloning a project. Never edit node_modules, never commit it (the .gitignore already excludes it), and delete it freely if something seems broken: npm install rebuilds it.
Restarting automatically while you work
Node.js reads your code once, when it starts. To see a change you must stop and start again, which gets tiring. Since Node.js 18.11 there is a built-in fix: node --watch index.js restarts on every file change. That is our dev script, so you need no extra package such as nodemon.
Environment variables and .env
Passwords, database addresses and secret keys must not be written in code, because code goes into Git and Git history is permanent. They also differ from computer to computer: your laptop uses a local database and your server uses a hosted one. The solution is environment variables, read in code as process.env.NAME.
During development it is awkward to set variables in the terminal each time, so the dotenv package reads a file called .env and loads its lines into process.env. The top line of index.js below does it: import 'dotenv/config'. The .env file stays on your machine (it is in .gitignore). What you do commit is .env.example, a copy with the names but no secrets, so that a new developer knows what to fill in.
# Copy this file to .env and fill it in. Never commit .env to Git.
PORT=5000
// Lesson 8: package.json, npm scripts and environment variables.
import 'dotenv/config'; // reads server/.env into process.env
const port = Number(process.env.PORT) || 5000;
console.log(`Job Tracker server would listen on port ${port}`);
console.log(`Running in ${process.env.NODE_ENV || 'development'} mode`);
Always read numbers with Number(...) and give a sensible default, as in Number(process.env.PORT) || 5000. Environment variables are always text, and a missing one is undefined.
Your task
- Create
server/.envby copying.env.example(do not commit it). Runcd server && npm install && npm run dev. - Change
PORTin.env. Becausenode --watchwatches your code files and not.env, stop the server with Ctrl + C and start it again to see the new value. - Run
npm run devwithNODE_ENV=productionset in your shell and read the second printed line. - Check that
git statusdoes not list.env(it should be ignored) but does list.env.example.
How to check it worked
- The server prints the port from your
.env. git statusnever shows.envornode_modules.
Summary
package.jsonlists dependencies and scripts; commitpackage-lock.json.node --watchrestarts on changes, with no extra package.- Secrets and settings live in
.env, never in Git; commit.env.exampleinstead.