Node.js Advanced: Security, Performance and Production
Configuration, Logging and Deployment
In this lesson you will
- Load configuration from environment variables safely
- Write useful structured logs
- Add health checks and graceful shutdown, and outline a container deployment
Introduction
Code that works on your laptop is not yet ready for production. Services need configuration that changes per environment, logs that explain what happened, a way for the platform to check health, and clean shutdowns. These habits turn a script into something operations teams can run.
Configuration from the environment
Settings that change between environments, such as ports, database locations and API keys, belong in environment variables, not in code.
For development, keep values in a .env file. Node can load it directly:
Terminal
node --env-file=.env app.jsWith a .env containing PORT=4321 and GREETING=hello from env, a script printing process.env.PORT and process.env.GREETING shows, in a real run:
4321 hello from envRules:
- Never commit
.envfiles with secrets. Add them to.gitignore. - Validate configuration at start-up and fail fast with a clear message if something required is missing, rather than failing later.
- Provide an
.env.examplelisting the names, without real values. - In production, use the platform's secrets store.
Quick quiz
Why validate required configuration when the app starts?
Logging
Logs are how you understand a running system.
- Write logs to standard output, one event per line, and let the platform collect them.
- Prefer structured logs (JSON), which tools can search and filter:
- Use levels: error, warn, info and debug, and control the verbosity with configuration.
- Include a request ID so you can follow one request across log lines and services.
- Never log passwords, tokens, full card numbers or other sensitive data. Be careful with personal data.
- Libraries such as Pino provide fast structured logging.
Health checks
Platforms need to know whether your service is working. Add simple endpoints:
A liveness check says the process is running. A readiness check says it can serve traffic, for example the database is reachable. Do not make health checks expensive.
Graceful shutdown
When a platform stops your service, it sends the signal SIGTERM. Finish current requests, close connections and exit:
Also handle crashes deliberately: log unhandled errors and exit, so a process manager or container platform restarts the service in a clean state, instead of leaving it half-broken.
Running in a container
A small Dockerfile, shown for reading:
Dockerfile
FROM node:24-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
USER node
ENV NODE_ENV=production
CMD ["node", "app.js"]npm ciinstalls exactly what the lock file says.--omit=devleaves out development tools.USER nodeavoids running as root.- Use the exec form of
CMD, so signals reach Node and graceful shutdown works.
Review the Docker courses for more on building, securing and deploying containers.
Release habits
- Run tests and audits in a pipeline before deploying.
- Deploy small changes and keep a quick rollback.
- Monitor error rates, response times and resource use after each release.
- Set timeouts on outgoing requests, since a hung dependency can hang you too.
Try it yourself
Add to your API: configuration with validation at start-up, JSON request logs with a request ID, a /healthz route and graceful shutdown. Write the Dockerfile and list what you would check before deploying.
Summary
- Keep configuration in environment variables, validate it at start-up and never commit secrets.
- Write structured logs to standard output, with request IDs and no sensitive data.
- Add health checks and graceful SIGTERM handling, and run in a non-root container using the exec form of CMD.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading