SyntaxStudy
Sign Up
Express.js Environment Configuration and Health Checks
Express.js Beginner 1 min read

Environment Configuration and Health Checks

Production Express applications must load configuration exclusively from environment variables — never from hard-coded values or committed `.env` files. The `dotenv` package loads a local `.env` file in development; in production, environment variables are injected by the deployment platform (Heroku config vars, AWS Parameter Store, Kubernetes Secrets). A `/health` endpoint that returns 200 when the application is healthy and 503 when it is not is required for load balancers and orchestrators to know whether to route traffic to the instance. A comprehensive health check verifies database connectivity, cache availability, and any critical external service. Keep the response JSON so monitoring tools can parse it. Graceful shutdown is equally important. When the process receives SIGTERM (from PM2, Kubernetes, or the OS), the app should stop accepting new connections, finish serving in-flight requests, close database connection pools, and then exit. Without graceful shutdown, users experience abrupt errors during deployments.
Example
// server.js – production entry point
require('dotenv').config(); // no-op in prod if no .env file
const app  = require('./app');
const db   = require('./db');           // Sequelize/Mongoose instance
const PORT = process.env.PORT || 3000;

// ── Health check ──────────────────────────────────────────────
app.get('/health', async (req, res) => {
    try {
        await db.authenticate(); // verify DB connection
        res.json({ status: 'ok', uptime: process.uptime() });
    } catch (err) {
        res.status(503).json({ status: 'error', detail: err.message });
    }
});

// ── Start server ──────────────────────────────────────────────
const server = app.listen(PORT, () => {
    console.log(`Listening on port ${PORT} (${process.env.NODE_ENV})`);
});

// ── Graceful shutdown ─────────────────────────────────────────
async function shutdown(signal) {
    console.log(`${signal} received – shutting down gracefully`);
    server.close(async () => {
        await db.close();
        console.log('DB connection closed. Exiting.');
        process.exit(0);
    });
    // Force exit after 10 s if connections don't close
    setTimeout(() => process.exit(1), 10_000).unref();
}

process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT',  () => shutdown('SIGINT'));