Skip to content

Freshworks Full Stack with Node.js Interview Questions & Answers

Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.

About Freshworks hiring for Full Stack with Node.js roles

Freshworks is a software-as-a-service company founded in Chennai that builds customer service, IT service management and sales software such as Freshdesk, Freshservice and Freshsales. Its India offices host most of its product and engineering teams. It hires for software engineers, QA engineers, data engineers and analysts.

For Full Stack with Node.js roles, this Freshworks practice set focuses most on Authentication and Security (7), Deployment, Scaling and Performance (7), Databases: MongoDB, SQL and Redis (5), Testing and Debugging (4). It has 1 easy, 17 medium, 12 hard questions, so you can start easy and work up to the harder ones.

Company type
Product
Headquarters
San Mateo, California, USA
Main India offices
Chennai, Bengaluru, Hyderabad

Freshworks Full Stack with Node.js interview process

  1. Online coding assessment
  2. Technical round 1 (DSA)
  3. Technical round 2 (design or domain)
  4. Hiring manager round
  5. HR round

Typical pattern based on public candidate experiences. Rounds vary by role, team and year.

Solved for FreshworksStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

Compare Prisma, Sequelize and TypeORM for SQL databases in Node.js.

Save to ▾
Show answer
Prisma uses a schema file to generate a fully typed client and has excellent TypeScript support and migrations, though complex raw SQL needs escape hatches. Sequelize is mature, promise-based and widely used in older JavaScript projects. TypeORM uses decorators and entity classes, familiar to Java and NestJS developers. Drizzle is a newer lightweight, SQL-like typed option. Pick based on TypeScript use and team familiarity.
02

How do you implement rate limiting on a login endpoint?

Save to ▾
Show answer
const rateLimit = require('express-rate-limit'); const { RedisStore } = require('rate-limit-redis'); const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, limit: 5, standardHeaders: 'draft-7', legacyHeaders: false, keyGenerator: (req) => `${req.ip}:${req.body.email}`, store: new RedisStore({ sendCommand: (...a) => redis.sendCommand(a) }) }); app.post('/auth/login', loginLimiter, login); // Add account lockout or CAPTCHA after repeated failures.
03

Where should a web app store tokens: localStorage or cookies?

Save to ▾
Show answer
localStorage is readable by any JavaScript on the page, so an XSS bug can steal tokens. HttpOnly, Secure, SameSite cookies cannot be read by JavaScript, which is safer for refresh tokens and session IDs. Cookies require CSRF protection, which SameSite=Lax or Strict plus CSRF tokens provide. A common pattern keeps the access token in memory and the refresh token in an HttpOnly cookie.
04

What is SQL injection and how do you prevent it in Node.js?

Save to ▾
Show answer
SQL injection happens when user input is concatenated into a query, letting attackers change it, for example ' OR 1=1 --. Prevent it with parameterised queries, such as pool.query('SELECT * FROM users WHERE email = $1', [email]) in pg, or an ORM like Prisma or Sequelize that parameterises automatically. Also validate input and give the database user minimum privileges.
05

Your app gets 'too many connections' errors from PostgreSQL after scaling to 20 pods. What would you do?

Save to ▾
Show answer
Each pod opens its own pool, so 20 pods with max 20 connections need 400, beyond the database limit. Reduce the per-pod pool size, put PgBouncer or RDS Proxy in front of the database for transaction pooling, and make sure connections are released, for example client.release() in finally blocks. Also check for long-running idle transactions holding connections.
06

Implement the cache-aside pattern with Redis for a product lookup.

Save to ▾
Show answer
async function getProduct(id) { const key = `product:${id}`; const cached = await redis.get(key); if (cached) return JSON.parse(cached); const product = await Product.findById(id).lean(); if (product) { await redis.set(key, JSON.stringify(product), { EX: 300 }); } return product; } async function updateProduct(id, data) { await Product.updateOne({ _id: id }, data); await redis.del(`product:${id}`); // invalidate }
07

What metrics would you monitor for a Node.js API in production?

Save to ▾
Show answer
Use the RED method for requests: rate, errors and duration with p50, p95 and p99. Add Node-specific metrics: event loop lag, heap used, garbage collection time and active handles, plus CPU, memory and restarts. Monitor dependencies such as database query time, pool usage and cache hit ratio. Export with prom-client or OpenTelemetry and alert on symptoms users feel.
08

Your service calls three microservices and fails completely if one is down. How would you make it more resilient?

Save to ▾
Show answer
Use Promise.allSettled so one failure does not reject everything, and return partial data with clear flags. Add timeouts to every call, retries with backoff for transient errors and a circuit breaker such as opossum to stop hammering a failing service. Provide fallbacks like cached values and log failures with correlation IDs so the issue can be traced.
09

npm audit reports a critical vulnerability in a dependency of a dependency. What do you do?

Save to ▾
Show answer
First check whether the vulnerable code path is actually reachable in our usage and read the advisory. Try npm audit fix or updating the parent package to a version that pulls a patched sub-dependency. If none exists, use the overrides field in package.json to force a safe version and run tests. Track it in a ticket and enable Dependabot or Renovate for ongoing updates.
10

How do you read a large file efficiently in Node.js?

Save to ▾
Show answer
const fs = require('fs'); const readline = require('readline'); async function countErrors(path) { const rl = readline.createInterface({ input: fs.createReadStream(path), crlfDelay: Infinity }); let count = 0; for await (const line of rl) { if (line.includes('ERROR')) count++; } return count; } // Streams line by line, so a 5 GB log uses little memory.
11

Production shows intermittent 502 errors from the load balancer but your app logs show nothing. How do you investigate?

Save to ▾
Show answer
A 502 means the load balancer got a bad or no response from the app. Check whether pods restarted or crashed through OOM kills, health check failures and deployment times. A common Node cause is keep-alive mismatch: set server.keepAliveTimeout higher than the load balancer idle timeout and headersTimeout above that. Also check event loop blocking and connection limits.
12

How do you prevent a cache stampede when a popular key expires?

Save to ▾
Show answer
When a hot key expires, thousands of requests may hit the database at once. Solutions: allow only one request to rebuild the cache using a short Redis lock while others wait or serve stale data, refresh hot keys in the background before expiry, add random jitter to TTLs so keys do not expire together, and use stale-while-revalidate where slightly old data is acceptable.
13

Your Node.js API becomes unresponsive when one endpoint generates a large PDF report. What is happening and how do you fix it?

Save to ▾
Show answer
The PDF generation is CPU-bound and blocks the single event loop, so every other request waits. Fixes: move the work to a worker_threads pool such as Piscina, or push it to a background job queue like BullMQ with Redis and return a job ID that the client polls. Also break large loops into chunks and measure event loop lag to confirm the fix.
14

How do you test Express routes with Supertest?

Save to ▾
Show answer
const request = require('supertest'); const app = require('../app'); // export app without calling listen describe('GET /api/v1/users/:id', () => { it('returns 404 for an unknown user', async () => { const res = await request(app) .get('/api/v1/users/000000000000000000000000') .set('Authorization', `Bearer ${testToken}`); expect(res.status).toBe(404); expect(res.body.error).toBeDefined(); }); });
15

What are health check endpoints and what is the difference between liveness and readiness?

Save to ▾
Show answer
Health endpoints let orchestrators check the app. Liveness answers whether the process is alive; if it fails, the container is restarted, so keep it simple. Readiness answers whether the instance can serve traffic, checking database and cache connections; if it fails, the load balancer stops sending requests but does not restart it. During shutdown, fail readiness first.
16

Write a retry function with exponential backoff for a flaky API call.

Save to ▾
Show answer
async function retry(fn, retries = 3, baseMs = 200) { for (let attempt = 0; ; attempt++) { try { return await fn(); } catch (err) { if (attempt >= retries) throw err; const delay = baseMs * 2 ** attempt + Math.random() * 100; await new Promise((r) => setTimeout(r, delay)); } } } await retry(() => paymentClient.getStatus(id));
17

What is the MongoDB aggregation pipeline? Give an example.

Save to ▾
Show answer
// Top 5 cities by revenue in the last 30 days const since = new Date(Date.now() - 30 * 864e5); const result = await Order.aggregate([ { $match: { status: 'paid', createdAt: { $gte: since } } }, { $group: { _id: '$city', revenue: { $sum: '$amount' }, orders: { $sum: 1 } } }, { $sort: { revenue: -1 } }, { $limit: 5 } ]); // Each stage transforms documents; put $match early to use indexes.
18

Explain OAuth 2.0 and the Authorization Code flow with PKCE.

Save to ▾
Show answer
OAuth 2.0 lets an app access resources on a user's behalf without seeing their password, for example social login with an existing account. In Authorization Code with PKCE, the app creates a code verifier and sends its hash to the authorisation server. The user logs in and consents, the app receives a code and exchanges it plus the verifier for tokens. PKCE stops intercepted codes being reused.
19

Your service is expected to get ten times normal traffic during a festive sale. How do you prepare?

Save to ▾
Show answer
Load test at above the expected peak, then fix bottlenecks. Pre-scale instances and database capacity instead of relying only on autoscaling, warm caches, and put static and catalogue responses on a CDN. Add rate limits, queue non-critical work, set timeouts and circuit breakers, prepare feature flags to switch off heavy features, and have dashboards, alerts and an on-call plan ready.
20

Compare session-based authentication with JWT-based authentication.

Save to ▾
Show answer
Sessions store state on the server, often in Redis, and the client holds only a session ID cookie; logout and revocation are easy. JWTs are stateless, so any service can verify them without a lookup, which suits microservices and mobile apps, but revoking a token before expiry needs a denylist or short lifetimes. Many systems combine short-lived JWT access tokens with server-stored refresh tokens.
21

Tell me about a time you had to balance speed of delivery with technical quality.

Save to ▾
Show answer
Situation: sales needed a partner API in one week for a client launch. Task: deliver fast without creating a mess. Action: I agreed with my manager to ship the core endpoints with validation, auth and tests, and to defer caching and admin tooling, logging them as tickets with dates. Result: the partner went live on time, and we completed the deferred work in the next sprint as planned.
22

Write code to verify an HMAC signature on an incoming webhook in Express.

Save to ▾
Show answer
const crypto = require('crypto'); app.post('/webhooks/payment', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.get('X-Signature') || ''; const expected = crypto .createHmac('sha256', process.env.WEBHOOK_SECRET) .update(req.body) .digest('hex'); const ok = sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)); if (!ok) return res.status(401).end(); handleEvent(JSON.parse(req.body)); res.status(200).end(); });
23

Your JWT secret has leaked. What steps do you take?

Save to ▾
Show answer
Treat it as an incident. Generate a new secret and deploy it immediately, which invalidates all existing tokens and forces re-login. Revoke refresh tokens in the database, check logs for suspicious tokens or admin actions, and find how it leaked, for example a committed .env or logs. Move to a secrets manager, consider asymmetric RS256 keys with key IDs to rotate safely, and document the incident.
24

A mobile app team complains your API returns too much data and is slow on 4G. What would you change?

Save to ▾
Show answer
Add field selection like ?fields=id,name,price, smaller list representations with details on a separate endpoint, pagination with sensible limits and gzip or Brotli compression. Support ETag and Cache-Control so unchanged data returns 304. If many screens need combined data, consider a Backend-for-Frontend layer or GraphQL tailored to the mobile app.
25

How do you design an API that needs to handle 50,000 requests per second for reading product details?

Save to ▾
Show answer
Make the read path cache-heavy: CDN caching for public product pages, Redis cache for product details with high hit ratio, and database read replicas behind it. Run many stateless Node instances with autoscaling, keep responses small and compressed, and use keep-alive connections. Avoid cache stampedes with request coalescing or locks, and precompute data that is expensive to build.
26

How do you use a MongoDB transaction in Mongoose?

Save to ▾
Show answer
const session = await mongoose.startSession(); try { await session.withTransaction(async () => { await Account.updateOne( { _id: fromId, balance: { $gte: amount } }, { $inc: { balance: -amount } }, { session } ); await Account.updateOne({ _id: toId }, { $inc: { balance: amount } }, { session }); await Transfer.create([{ fromId, toId, amount }], { session }); }); } finally { await session.endSession(); } // Requires a replica set or Atlas cluster.
27

Should you use serverless functions like AWS Lambda for a Node.js API?

Save to ▾
Show answer
Serverless suits spiky or low-traffic workloads, event processing and quick prototypes, since you pay per invocation and need no server management. Downsides are cold starts, execution time limits, connection handling with relational databases and harder local debugging. For steady high traffic or long-lived WebSocket connections, containers are usually cheaper and simpler. Many teams mix both.
28

How do you add a correlation ID to every log line for a request?

Save to ▾
Show answer
const { AsyncLocalStorage } = require('async_hooks'); const { randomUUID } = require('crypto'); const als = new AsyncLocalStorage(); app.use((req, res, next) => { const id = req.get('X-Request-Id') || randomUUID(); res.set('X-Request-Id', id); als.run({ requestId: id }, next); }); const log = (msg, extra = {}) => logger.info({ ...extra, requestId: als.getStore()?.requestId }, msg); // Pass the ID to downstream services in headers.
29

How do you load test a Node.js API before a big sale event?

Save to ▾
Show answer
Define targets from expected traffic, such as 5,000 requests per second with p95 under 300 ms. Write realistic scenarios in k6 or Artillery covering browse, cart and checkout, run them against a production-like environment, and ramp up gradually. Watch latency, error rates, CPU, memory, event loop lag and database metrics, then fix bottlenecks and rerun until targets are met with headroom.
30

When would you choose NestJS or Fastify over Express?

Save to ▾
Show answer
Choose Fastify when raw performance and built-in schema validation matter; it is faster than Express thanks to optimised routing and serialisation. Choose NestJS for large teams that want structure: modules, dependency injection, decorators and first-class TypeScript, similar to Spring or Angular. Express still suits small to medium services and teams that prefer flexibility and a huge middleware ecosystem.

Tips to crack the Freshworks Full Stack with Node.js interview

  • Use Freshdesk or Freshservice free trials to understand ticketing, SLAs and automation workflows.
  • Practise DSA and Ruby, Java or Python fundamentals, depending on the team's tech stack.
  • Read about Freshworks' journey from Chennai to a US-listed SaaS company and its focus on mid-market customers.
  • Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
  • Practise the hard questions on this page aloud; Freshworks interviewers usually ask follow-ups on your first answer.

Frequently asked questions

How many rounds are there in the Freshworks Full Stack with Node.js interview?

Candidates usually go through 5 stages: Online coding assessment; Technical round 1 (DSA); Technical round 2 (design or domain); Hiring manager round; HR round. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.

Which topics should I prepare for the Freshworks Full Stack with Node.js interview?

This practice set leans on Authentication and Security (7), Deployment, Scaling and Performance (7), Databases: MongoDB, SQL and Redis (5), Testing and Debugging (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Freshworks interviewers ask you to walk through real work.

Are these the exact questions asked at Freshworks?

No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like Freshworks's. They are not a leaked or verified list of past questions.

Where does Freshworks hire Full Stack with Node.js professionals in India?

Freshworks has large teams in Chennai, Bengaluru, Hyderabad. Openings and locations change often, so check the Freshworks careers page and filter by city and experience.

Full Stack with Node.js questions for similar companies