Node.js case studies

30 Node.js case studies available. Levels: fundamental (10), advanced (10), expert (10).
FundamentalNode.js

Building a REST API with Express and basic routing

Context A backend team needs a simple CRUD API for managing a list of products stored in memory. The Problem All logic is currently in a single index.js file with nested callbacks, making the code hard to read and extend. Constraints Use Express to define GET, POST, PUT, and DELETE routes for /products. Store products in an in-memory array. Return appropriate HTTP status codes for each operation. Expected Deliverable An Express REST API with four CRUD routes for a products resource, using in-memory storage and correct status codes.

nodejsexpressrest-api+2
FundamentalNode.js

Connecting to a MongoDB database with Mongoose

Context A Node.js API needs to persist user data to a MongoDB database using a schema-based approach. The Problem The team is using raw MongoDB driver queries with no schema validation, leading to inconsistent document structures in the database. Constraints Define a Mongoose schema and model for a User (name, email, createdAt). Connect to MongoDB using the connection string from an environment variable. Implement a save and find operation using the model. Expected Deliverable A Node.js module using Mongoose to define a User schema, establish a database connection from an environment variable, and perform basic CRUD operations.

nodejsmongoosemongodb+2
FundamentalNode.js

Creating a simple CLI tool with process.argv

Context A developer wants a command-line script that accepts a filename as an argument and counts the number of lines in that file. The Problem The filename is currently hard-coded in the script, requiring a code change every time a different file needs to be processed. Constraints Read the filename from process.argv[2]. Display a usage message if no argument is provided. Use fs.promises to read the file and count line breaks. Handle file not found errors gracefully. Expected Deliverable A Node.js CLI script that accepts a filename argument, reads the file, counts and prints the number of lines, and handles missing arguments and file errors.

nodejscliprocess-argv+2
FundamentalNode.js

Creating an HTTP server with Node.js built-in http module

Context A team needs a lightweight HTTP server to serve a simple health check endpoint for a microservice. The Problem The team is not familiar with Node.js and has been using a full Express setup for a server that only needs one route. Constraints Use only the built-in http module, no external packages. Respond with a JSON body on GET /health. Return a 404 status for all other routes. Expected Deliverable A Node.js HTTP server using the built-in http module, handling a health check endpoint and returning appropriate status codes.

nodejshttpserver+2
FundamentalNode.js

Creating and using npm modules with CommonJS and ES modules

Context A utility library with math helper functions needs to be shared across multiple Node.js scripts in the same project. The Problem All utility functions are copy-pasted into every script that needs them, creating maintenance inconsistencies. Constraints Create a utils.js module exporting at least three functions. Import the module in another file using require() (CommonJS). Convert both files to use ES module syntax (import/export) and update package.json accordingly. Expected Deliverable A Node.js utility module demonstrating both CommonJS and ES module syntaxes, with correct package.json configuration for each approach.

nodejsmodulescommonjs+2
FundamentalNode.js

Handling environment variables with dotenv

Context A Node.js application connects to a database using credentials currently hard-coded in the source code, creating a security risk. The Problem Database credentials and API keys are committed to the git repository in plain text. Current Code const db = connect("postgres://admin:secret123@localhost/mydb"); Constraints Use the dotenv package to load variables from a .env file. Access credentials via process.env. Add .env to .gitignore and provide a .env.example template. Expected Deliverable A Node.js application loading all sensitive configuration from environment variables using dotenv, with a .env.example file documenting required variables.

nodejsdotenvenvironment+2
FundamentalNode.js

Implementing basic error handling middleware in Express

Context An Express application crashes with unhandled errors that reach the client as HTML error pages instead of JSON responses. The Problem There is no centralized error handling, so every route must individually handle errors or the default Express handler exposes stack traces to clients. Constraints Create a four-argument Express error middleware (err, req, res, next). Catch errors thrown in routes using next(err). Return JSON error responses with status code and message. Log the error stack to the console. Expected Deliverable An Express application with a centralized error handling middleware returning JSON error responses and preventing stack trace exposure.

nodejsexpresserror-handling+2
FundamentalNode.js

Parsing incoming JSON request bodies in Express

Context An Express API endpoint receives POST requests with a JSON body but the request body is always undefined. The Problem The express.json() middleware is not configured, so incoming request bodies are never parsed. Current Code app.post("/users", (req, res) => { console.log(req.body); // undefined res.sendStatus(200); }); Constraints Add the express.json() middleware globally before route definitions. Validate that required fields (name, email) are present in the body. Return a 400 error with a message if validation fails. Expected Deliverable An Express endpoint correctly parsing JSON request bodies, with basic field validation and appropriate error responses.

nodejsexpressmiddleware+2
FundamentalNode.js

Reading and writing files with the fs module

Context A script must read a JSON configuration file, modify one field, and write the updated content back to disk. The Problem The developer is using synchronous blocking calls (fs.readFileSync) inside an async context, causing event loop blocking. Current Code const data = fs.readFileSync("config.json"); const config = JSON.parse(data); config.version = "2.0"; fs.writeFileSync("config.json", JSON.stringify(config)); Constraints Replace synchronous calls with fs.promises equivalents. Use async/await for readability. Handle file-not-found errors explicitly. Expected Deliverable A Node.js script using fs.promises to read, modify, and write a JSON file asynchronously with proper error handling.

nodejsfsasync+2
FundamentalNode.js

Running asynchronous tasks with Promise.all

Context A data aggregation script fetches information from three different APIs and combines the results into a single report. The Problem The current script awaits each API call sequentially, taking 3 seconds total when all three could run in parallel in 1 second. Current Code const a = await fetchA(); const b = await fetchB(); const c = await fetchC(); Constraints Refactor to run all three fetch calls in parallel with Promise.all. Handle the case where any one of them fails without blocking the others using Promise.allSettled. Log which calls succeeded and which failed. Expected Deliverable A Node.js script using Promise.all and Promise.allSettled to run concurrent async operations with individual failure handling.

nodejspromisesasync+2
AdvancedNode.js

Building a rate limiter middleware from scratch

Context A public API is being abused by scripts making thousands of requests per minute from the same IP address. The Problem There is no rate limiting in place, exposing the service to denial-of-service attacks and resource exhaustion. Constraints Implement a sliding window rate limiter using a Redis store. Allow 100 requests per minute per IP. Return a 429 status with a Retry-After header when the limit is exceeded. Do not use any existing rate-limit library. Expected Deliverable A custom Express rate limiting middleware using Redis and the sliding window algorithm, returning correct 429 responses with retry guidance.

nodejsrate-limitingredis+2
AdvancedNode.js

Building a WebSocket server for real-time notifications

Context A dashboard application polls the server every 5 seconds for new notifications, generating unnecessary traffic when nothing has changed. The Problem HTTP polling creates constant load and introduces up to 5 seconds of notification latency. Constraints Implement a WebSocket server using the ws library. Push notifications to connected clients when an event occurs. Manage client connections in a Map keyed by user ID. Handle client disconnection and reconnection gracefully. Expected Deliverable A Node.js WebSocket server pushing targeted real-time notifications to connected clients by user ID, with connection lifecycle management.

nodejswebsocketreal-time+2
AdvancedNode.js

Caching API responses with Redis and cache invalidation

Context A product catalog endpoint performs an expensive database query on every request, resulting in slow response times during peak traffic. The Problem There is no caching layer, so identical read requests repeatedly hit the database even when the data has not changed. Constraints Cache the query result in Redis with a TTL of 60 seconds. Return the cached value on subsequent requests within the TTL window. Invalidate the cache entry when a product is updated or deleted. Use a consistent cache key naming convention. Expected Deliverable An Express endpoint with Redis-based response caching, TTL expiry, and explicit cache invalidation on write operations.

nodejsrediscaching+2
AdvancedNode.js

Implementing a job queue with Bull and Redis

Context An application sends transactional emails synchronously inside request handlers, causing slow API response times and dropped emails when the mail server is slow. The Problem Email sending blocks the HTTP response cycle and has no retry mechanism for failed deliveries. Constraints Use Bull to create an email queue backed by Redis. Add email jobs to the queue inside the request handler and respond immediately. Implement a worker that processes jobs with retry on failure (3 retries, exponential backoff). Handle failed jobs by logging to a dead-letter log. Expected Deliverable A Node.js application offloading email sending to a Bull queue, with a background worker, retry logic, and dead-letter handling.

nodejsbullqueue+2
AdvancedNode.js

Implementing database migrations with a versioned migration system

Context A Node.js application modifies the database schema manually in production, causing inconsistencies between environments and no rollback capability. The Problem There is no migration tracking, so schema changes are applied inconsistently across development, staging, and production environments. Constraints Use the node-pg-migrate or Knex migration system. Write a versioned up and down migration for adding a new table. Integrate migration execution into the application startup sequence. Document how to roll back a migration. Expected Deliverable A Node.js project with a versioned migration system, at least one up/down migration pair, and startup-time migration execution.

nodejsmigrationsdatabase+2
AdvancedNode.js

Implementing JWT authentication with refresh token rotation

Context An Express API needs a secure authentication system using short-lived access tokens and long-lived refresh tokens. The Problem The current system issues access tokens with a 30-day expiry and no refresh mechanism, making token revocation impossible. Constraints Issue access tokens with a 15-minute expiry using jsonwebtoken. Issue refresh tokens with a 7-day expiry stored in an httpOnly cookie. Implement a /auth/refresh endpoint that rotates the refresh token on each use. Invalidate the old refresh token immediately after rotation. Expected Deliverable An Express authentication system with JWT access tokens, refresh token rotation via httpOnly cookies, and invalidation logic to prevent token reuse.

nodejsjwtauthentication+2
AdvancedNode.js

Securing an API with input validation using Joi or Zod

Context An Express API receives user-submitted data that is passed directly to database queries without validation, exposing the application to injection and data integrity issues. The Problem No input validation is performed on incoming request bodies, query parameters, or route parameters. Constraints Define validation schemas for request bodies and query parameters using Zod or Joi. Create a reusable validation middleware that applies the schema and returns 422 with detailed error messages on failure. Apply the middleware to at least three routes. Expected Deliverable An Express API with a reusable schema validation middleware using Zod or Joi, returning structured 422 error responses for invalid inputs.

nodejsvalidationzod+2
AdvancedNode.js

Streaming large file uploads to S3 without buffering in memory

Context An API endpoint receives video file uploads that are buffered entirely in memory before being saved, causing frequent OutOfMemory crashes on large files. The Problem The current implementation uses multer with memoryStorage, loading the full file into a Buffer before any processing. Constraints Stream the upload directly to Amazon S3 using the AWS SDK v3 Upload class. Use multer with a custom storage engine or pipe the raw request stream. Never buffer the entire file in memory. Expected Deliverable An Express endpoint streaming file uploads directly to S3 using piped streams, with no full in-memory buffering regardless of file size.

nodejsstreamings3+2
AdvancedNode.js

Structuring a Node.js project with layered architecture

Context A growing Express application has all business logic mixed directly into route handlers, making it untestable and hard to maintain. The Problem Route files contain database queries, business rules, and HTTP response logic all at the same level, with no separation of concerns. Constraints Separate the codebase into routes, controllers, services, and repositories layers. Each layer communicates only with the one directly below it. Define clear interfaces between layers using dependency injection. Expected Deliverable A refactored Express application following a layered architecture (routes, controllers, services, repositories), demonstrating clear separation of concerns and testable service logic.

nodejsarchitecturelayered+2
AdvancedNode.js

Writing unit tests for Express services with Jest and mocking

Context A user service containing business logic has no tests. Every change requires manual verification and regressions frequently reach production. The Problem The service has no test coverage, and its dependencies (database, external APIs) make it hard to test in isolation. Constraints Write Jest unit tests for at least three service functions. Mock all external dependencies using jest.mock(). Test both success paths and error paths. Achieve 80 percent or more code coverage for the service module. Expected Deliverable A Jest test suite for a Node.js service module, with mocked dependencies, coverage of happy and error paths, and at least 80 percent code coverage.

nodejsjestunit-testing+2
ExpertNode.js

Architecting a Node.js serverless backend with AWS Lambda and cold start optimization

Context A serverless API built on AWS Lambda experiences cold start latencies of 3-5 seconds on the first request, making the application feel broken to users. The Problem The Lambda functions import heavy dependencies at the module level and initialize database connections inside the handler, causing maximum cold start overhead. Constraints Move database connection initialization outside the handler to reuse across warm invocations. Use Lambda layers to share common dependencies across functions. Implement provisioned concurrency for latency-sensitive endpoints. Measure cold start reduction with before-and-after metrics. Expected Deliverable A Node.js Lambda architecture with optimized cold starts via connection reuse, shared layers, and provisioned concurrency, with documented latency improvements.

nodejslambdaserverless+2
ExpertNode.js

Building a GraphQL API with DataLoader to solve the N+1 problem

Context A GraphQL API resolving a list of posts with their authors triggers one database query per post to fetch the author, causing 101 queries for a list of 100 posts. The Problem Nested resolvers run independently per item, generating an N+1 query pattern that degrades performance at scale. Constraints Implement DataLoader to batch and cache author lookups per request. Instantiate a fresh DataLoader per request to prevent data leakage between users. Demonstrate the reduction from N+1 to 2 queries with a query log. Expected Deliverable A Node.js GraphQL API using DataLoader to batch database calls, reducing N+1 query patterns to batched queries with per-request cache isolation.

nodejsgraphqldataloader+2
ExpertNode.js

Building a plugin-based CLI framework with dynamic command loading

Context A developer toolchain CLI must support third-party plugins that add new commands without modifying the core CLI source code. The Problem All commands are hard-coded in the main CLI file, requiring a version bump and republish to add new functionality. Constraints Design a plugin discovery mechanism that loads command modules from a configured directory or from installed npm packages matching a naming pattern. Each plugin exports a command definition (name, description, handler). Implement help generation from registered plugins dynamically. Expected Deliverable A Node.js CLI framework with dynamic plugin loading, auto-generated help from plugin metadata, and a sample plugin demonstrating the extension API.

nodejscliplugin-system+2
ExpertNode.js

Building a zero-downtime deployment pipeline with health checks and graceful shutdown

Context A Node.js service deployed on Kubernetes receives traffic during rolling updates, causing in-flight requests to fail when pods are terminated abruptly. The Problem The application does not handle SIGTERM gracefully, terminating active connections immediately when a new deployment starts. Constraints Implement a SIGTERM handler that stops accepting new connections and waits for in-flight requests to complete before exiting. Expose /healthz and /readyz endpoints for Kubernetes liveness and readiness probes. Set a maximum drain timeout of 30 seconds. Expected Deliverable A Node.js application with graceful shutdown on SIGTERM, Kubernetes-compatible health check endpoints, and a configurable drain timeout ensuring zero dropped requests during rolling deploys.

nodejsgraceful-shutdownkubernetes+2
ExpertNode.js

Building an event-driven microservices system with RabbitMQ

Context An e-commerce platform must decouple its order, inventory, and notification services so they can scale and deploy independently. The Problem All three services are tightly coupled via direct HTTP calls. A failure in the notification service blocks order processing. Constraints Publish domain events (OrderPlaced, StockReserved) to RabbitMQ exchanges. Each consuming service subscribes to relevant events via dedicated queues. Implement a dead-letter exchange for failed processing. Ensure at-least-once delivery with idempotent consumers. Expected Deliverable A Node.js event-driven architecture with RabbitMQ, demonstrating publish-subscribe between three services, dead-letter handling, and idempotent event consumers.

nodejsrabbitmqevent-driven+2
ExpertNode.js

Designing a multi-tenant SaaS API with row-level security

Context A SaaS platform serves multiple organizations from a single database. Data isolation between tenants must be enforced at the application and database levels. The Problem Tenant isolation is currently implemented only in application code. A bug in any middleware layer could leak data across tenants. Constraints Implement row-level security in PostgreSQL using tenant_id policies. Inject the tenant context from the JWT into the database session using SET LOCAL. Build a middleware that extracts the tenant from the token and sets the session variable. Write tests proving cross-tenant data access is impossible. Expected Deliverable A Node.js multi-tenant API enforcing data isolation at the database level via PostgreSQL row-level security, with tenant context injected from JWT claims.

nodejsmulti-tenantrls+2
ExpertNode.js

Implementing a CQRS pattern with event sourcing in Node.js

Context A financial ledger application must maintain a complete audit trail of all balance changes and support point-in-time balance reconstruction. The Problem The current mutable state model overwrites previous values, making it impossible to audit how a balance reached its current state. Constraints Store every state change as an immutable event in an event store. Reconstruct current state by replaying the event stream. Separate the write model (commands) from the read model (queries). Implement a snapshot mechanism to avoid replaying the full history. Expected Deliverable A Node.js CQRS and event sourcing implementation for a ledger, with event store, state reconstruction, separated read/write models, and snapshot optimization.

nodejscqrsevent-sourcing+2
ExpertNode.js

Implementing a distributed tracing system with OpenTelemetry

Context A microservices architecture spanning five Node.js services has no observability. Debugging latency issues requires manually correlating logs across services. The Problem There is no trace correlation between services, making it impossible to follow a single request through the entire system. Constraints Instrument each service with the OpenTelemetry Node.js SDK. Propagate trace context via HTTP headers (W3C TraceContext). Export spans to Jaeger or Zipkin. Add custom span attributes for business context (userId, orderId). Expected Deliverable A Node.js multi-service setup fully instrumented with OpenTelemetry, propagating trace context across HTTP calls and exporting spans to a distributed tracing backend.

nodejsopentelemetrydistributed-tracing+2
ExpertNode.js

Implementing a real-time leaderboard with sorted sets in Redis

Context A gaming platform must display a live leaderboard of the top 100 players, updated in real-time as scores change. The Problem The current implementation runs a full table scan and sort on the database on every page load, becoming unacceptably slow at 1 million players. Constraints Store player scores in a Redis Sorted Set using ZADD. Retrieve the top 100 with ZREVRANGE with scores. Update scores atomically with ZINCRBY. Push leaderboard updates to connected clients via WebSocket when the top 100 changes. Expected Deliverable A Node.js real-time leaderboard using Redis Sorted Sets for O(log N) score updates, with WebSocket-based live push to clients when rankings change.

nodejsredissorted-sets+2
ExpertNode.js

Securing a Node.js API against OWASP Top 10 vulnerabilities

Context A production Express API is preparing for a security audit and must address the most critical OWASP API vulnerabilities. The Problem The API has no protection against injection, broken authentication, security misconfiguration, or mass assignment attacks. Constraints Address at minimum: SQL injection prevention (parameterized queries), mass assignment (explicit field whitelisting), security headers (helmet), brute force protection on auth endpoints, and sensitive data exposure (no stack traces in responses). Document each mitigation with the corresponding OWASP category. Expected Deliverable A hardened Express API addressing at least five OWASP Top 10 API vulnerabilities, with documented mitigations and automated security tests.

nodejsowaspsecurity+2

Original questions designed by CodeDuel. CodeDuel is not affiliated with any publisher or certification body mentioned; certification names and trademarks belong to their respective owners and are used only to indicate the area covered. Report content

    Node.js case studies: 30 scenarios | CodeDuel