Skip to content
Prajwal Bhatia

Prajwal Bhatia

Senior Frontend Engineer

I like taking complex problems, breaking them down, and turning them into simple frontend solutions.

React, TypeScript, JavaScript, Next.js, Redux · RTK Query, Node · Express, BullMQ · Redis, Puppeteer · GCS, Jest · RTL, Core Web Vitals, Datadog RUM · Sentry, Material UI, Accessibility

SelectedWork

PerformanceCore Web VitalsDatadog RUM

How I cut LCP from 5.45s to 3.17s on our busiest flow

5.45s3.17s

LCP p75

batch selection · 42% faster

0.2290.006

CLS p75

intern profile

9.9s8.6s

LCP p75

onboarding

0.440.24

CLS p75

dashboard

Batch selection · highest-traffic flow · field data at p75

Drag the timeline. Same page, before and after my work.

6.00s

Before

LCP 5.45s · CLS 0.229

A late banner arrives and shoves everything down. That jump is the 0.229 CLS.

After

LCP 3.17s · CLS 0.006

Done at 3.17s, and not a single pixel shifted on the way.

0s6s
3.17s — after LCP5.45s — before LCP
ArchitectureBackendNodeBullMQ

How I filled a browse page that was mostly empty boxes

~55%

of URLs via og:image

in about a second

8×

lower latency

vs the Puppeteer fallback

95%

success in production

2 tiers

og:image, then Puppeteer

The same intern row showing two generated thumbnails of the intern's actual project pagesAn intern row on the browse page showing two generic paperclip placeholders where project previews should be
Candidate name, institution and previous employer redacted
ProductReliabilityReactRTK Query

Making a long application finishable

28 min12 min

Time to apply

57% faster

+24%

completion rate

−31%

drop-off

5–8

steps

by batch config

The résumé-profile step of the application. A rail on the left marks seven steps with the sixth active, the heading reads Step 6 of 7, and the main action offers to autofill the profile from an uploaded résumé.
ArchitectureProductReactTypeScript

How I collapsed three sequential calls into one

3+1

Sequential API calls

one transactional endpoint

31

Signup screens

registration page deleted

BEFOREScreen 1call 1Screen 2call 2Screen 3call 3each call waits on the last · partial state accumulates before anything commitsAFTEROne screenOne transactional callcountry + timezone inferred, not askedthe registration screen was deleted, not merged
“3+” is a floor, not a count — the old frontend made three or more sequential calls depending on the path taken.

Experience

04/2025 — now

Activation & onboarding

Redesigned intern activation & application flow

+24%
completion rate
↓31%
drop-off
3 mo
to ship

One of nine engineers on it. The auto-save and draft-recovery layer is mine end to end.

Batch Selection

A 500-line component split into focused hooks

Redux thunks migrated to RTK Query with caching and deduplication; business rules moved server-side.

Thumbnail pipeline

95%

success in production

Fast path

8×

lower latency than the Puppeteer fallback

Virtualised filter

10+

autocomplete and filter surfaces

Shared frontend repo

Résumé Builder

plus accessibility, testing, CI and dependency hygiene

01/2023 — 04/2025

Core Web Vitals

5.45s → 3.17s

Batch Selection LCP p75 — 42% faster, through image preloading, third-party preconnects and deferred analytics.

Layout shift

0.229 → 0.006

Intern Profile CLS p75

Platform scale

285K+

active applications

Companies

23K+

on the platform

Migration

EUI + Ant Design → Material UI

drawers, modals, navigation, file pickers, timelines and forms

07/2021 — 01/2023

Video platform

Playback owned end to end

Background downloads for students on unreliable connections, session activity tracking and milestone instrumentation.

Components

Reusable React

refactored out of legacy modules

08/2019 — 07/2021

API efficiency

50%

fewer calls — client-side caching, request deduplication and TTL-based invalidation

Interfaces

Responsive React

and REST API workflows

Hiring for a senior role?

Email is fastest — I answer everything.