Complete Guide to Running a Node.js Server
Back to Blog
Web Development

Complete Guide to Running a Node.js Server

AmbaJanuary 15, 20242 min read

Complete Guide to Running a Node.js Server

Running a Node.js server is a fundamental skill for modern web development. In this comprehensive guide, we'll cover everything from basic setup to production deployment, including best practices and common pitfalls to avoid.

Prerequisites

Before we begin, make sure you have:

  • Node.js installed on your system (Download from nodejs.org)
  • A code editor (VS Code recommended)
  • Basic knowledge of JavaScript
  • Terminal/Command Line familiarity

Basic Server Setup

Let's start with creating a basic HTTP server using Node.js:

// server.js
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, World!');
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});

To run this server:

node server.js

Express.js Server

While Node's built-in HTTP server works, Express.js makes server creation much easier:

// app.js
const express = require('express');
const app = express();

// Middleware for parsing JSON
app.use(express.json());

// Basic route
app.get('/', (req, res) => {
  res.send('Hello from Express!');
});

// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Setting Up Express

  1. Initialize your project:
mkdir my-node-server
cd my-node-server
npm init -y
  1. Install Express:
npm install express
  1. Create basic folder structure:
my-node-server/
├── node_modules/
├── src/
│   ├── routes/
│   ├── controllers/
│   ├── models/
│   └── middleware/
├── app.js
└── package.json

Adding Routes

Organize your routes in separate files:

// src/routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ message: 'Get all users' });
});

router.post('/', (req, res) => {
  res.json({ message: 'Create new user' });
});

module.exports = router;

Use routes in main app:

// app.js
const usersRouter = require('./src/routes/users');
app.use('/api/users', usersRouter);

Middleware

Middleware functions are crucial for request processing:

// src/middleware/logger.js
const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url} at ${new Date()}`);
  next();
};

// Error handling middleware
const errorHandler = (err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
};

// Use middleware
app.use(logger);
app.use(errorHandler);

Environment Configuration

Use environment variables for configuration:

// config.js
require('dotenv').config();

module.exports = {
  port: process.env.PORT || 3000,
  dbUrl: process.env.DATABASE_URL,
  nodeEnv: process.env.NODE_ENV || 'development'
};

Create a .env file:

PORT=3000
DATABASE_URL=mongodb://localhost:27017/myapp
NODE_ENV=development

Database Connection

Example with MongoDB:

// src/db/connection.js
const mongoose = require('mongoose');
const config = require('../config');

mongoose.connect(config.dbUrl, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.error('MongoDB connection error:', err));

Production Best Practices

  1. Use Process Managers

PM2 is recommended for production:

npm install -g pm2
pm2 start app.js --name "my-app"
  1. Security Measures
const helmet = require('helmet');
const cors = require('cors');

app.use(helmet()); // Security headers
app.use(cors());   // CORS handling
  1. Logging
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

API Examples

Here's a more complete API endpoint example:

// src/controllers/userController.js
const User = require('../models/user');

exports.getUsers = async (req, res) => {
  try {
    const users = await User.find();
    res.json(users);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

exports.createUser = async (req, res) => {
  try {
    const user = new User(req.body);
    const savedUser = await user.save();
    res.status(201).json(savedUser);
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
};

Testing

Set up testing with Jest:

// tests/user.test.js
const request = require('supertest');
const app = require('../app');

describe('User API', () => {
  test('GET /api/users should return all users', async () => {
    const res = await request(app).get('/api/users');
    expect(res.statusCode).toBe(200);
    expect(Array.isArray(res.body)).toBeTruthy();
  });
});

Deployment Checklist

  1. Set proper environment variables
  2. Implement logging
  3. Use process manager (PM2)
  4. Set up monitoring
  5. Configure security middleware
  6. Enable GZIP compression
  7. Set up SSL/TLS
  8. Configure proper error handling
  9. Set up database backups
  10. Implement rate limiting

Running in Development

For development, use nodemon for auto-reloading:

{
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "test": "jest"
  }
}

Common Issues and Solutions

  1. Port Already in Use
lsof -i :3000  # Find process using port 3000
kill -9 <PID>  # Kill the process
  1. Memory Leaks Use Node.js --inspect flag for debugging:
node --inspect app.js
  1. Unhandled Promises
process.on('unhandledRejection', (reason, promise) => {
  console.log('Unhandled Rejection at:', promise, 'reason:', reason);
});

Conclusion

Running a Node.js server involves many aspects, from basic setup to production deployment. Remember to:

  • Follow security best practices
  • Use appropriate middleware
  • Implement proper error handling
  • Set up monitoring and logging
  • Keep dependencies updated
  • Test thoroughly before deployment

Additional Resources