Installing & Setting Up Express
Getting an Express project running is a few commands — but the setup choices you make now (module system, dev tooling, project layout) shape everything after. This page walks through a clean, modern setup using ES modules and a sensible structure, and flags the small decisions that save pain later.
Initialize the project
Bash
mkdir my-api && cd my-api npm init -y # create package.json npm install express # add Express as a dependency
`express` goes in `dependencies`, not `devDependencies`
Express is needed at runtime, so a plain `npm install express` (which adds it to `dependencies`) is correct. Only build/test-time tools belong in `devDependencies`. If you're unsure of the distinction, see [Dependency Types](/nodejs/dependencies-types).
Choose ES modules
Add "type": "module" to package.json so you can use import syntax (the modern standard) instead of require:
package.json
JSON
{
"name": "my-api",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js"
},
"dependencies": {
"express": "^5.0.0"
}
}`import` requires `"type": "module"` (or a `.mjs` file)
Without `"type": "module"`, Node treats `.js` files as CommonJS and `import` statements throw `SyntaxError: Cannot use import statement outside a module`. Either set `"type": "module"` (recommended) or use `const express = require('express')`. Don't mix the two styles in one file. The module-system details are in [CommonJS vs ESM](/nodejs/module-wrapper).
Your entry file
server.js
JS
import express from 'express'
const app = express()
const PORT = process.env.PORT || 3000
app.get('/', (req, res) => {
res.send('Express is running!')
})
app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`)
})Read the port from the environment
`process.env.PORT || 3000` lets the hosting platform inject a port in production while defaulting to 3000 locally. Hardcoding a port breaks many deployment environments (they assign one and expect you to use it). Configuration via environment variables is standard practice — see [Environment Variables](/nodejs/environment-variables) later in the tutorial.
Auto-restart during development
Bash
# Built into modern Node (18.11+) — no dependency needed: node --watch server.js # The classic third-party tool (more features, older Node): npm install --save-dev nodemon npx nodemon server.js
`node --watch` replaces nodemon for most needs
Node now ships a built-in `--watch` flag that restarts the process when files change — covering the main reason people installed `nodemon`. Use `--watch` for simple projects; reach for `nodemon` only if you need its extra config (watch globs, delays, exec hooks). Either way, this is dev-only — production runs plain `node` (or a process manager).
A sensible project structure
Text
my-api/ ├── package.json ├── server.js # entry: create app, listen ├── app.js # configure app: middleware + routes (no listen) ├── routes/ │ ├── users.js # express.Router() modules │ └── posts.js ├── middleware/ │ └── auth.js ├── controllers/ # request handlers, separated from routing └── .env # local config (gitignored!)
Separate `app` (configuration) from `server` (listening)
A common pattern: `app.js` builds and exports the configured Express app (middleware + routes), and `server.js` imports it and calls `listen`. This separation makes the app **testable** — your tests import `app` and make requests against it without binding a real port. We'll use [Router modules](/nodejs/express-router) to keep routes out of one giant file.
Essential .gitignore
.gitignore
Text
node_modules/ .env *.log
Never commit `node_modules` or `.env`
`node_modules` is huge and reproducible from `package-lock.json` (`npm ci` rebuilds it), so committing it bloats the repo for no benefit. `.env` typically holds secrets (API keys, DB passwords) — committing it leaks credentials into git history, which is hard to fully scrub. Add both to `.gitignore` before your first commit.
Verify it works
Bash
npm run dev # then in another terminal: curl http://localhost:3000 # → Express is running!
Express is running!
Next
Build a real first app with multiple routes and JSON: [Your First Express App](/nodejs/express-first-app).