How to Fix INP in Next.js Apps
If your Next.js app looks loaded but still feels sticky when users click, tap, or type, you probably have an INP problem.
INP, or Interaction to Next Paint, measures how quickly a page responds to user interactions across the visit. According to web.dev, a good target is 200 milliseconds or less at the 75th percentile of page loads.
For Next.js teams, poor INP usually is not one mysterious framework issue.
It is usually a stack of avoidable decisions:
- too much client-side JavaScript
- too much work during hydration
- third-party scripts firing too early
- interaction handlers doing more work than they should
- large re-renders at the moment of input
The official sources behind this article are:
- Interaction to Next Paint (INP) on web.dev
- Optimize Interaction to Next Paint on web.dev
- Optimize long tasks on web.dev
- Next.js lazy loading guide
- Next.js Script component docs
If you want the adjacent reads in this cluster, also start here:
- Core Web Vitals for SaaS Landing Pages: What to Fix First
- LCP vs INP: Which Metric Is Hurting Your Conversions?
- Case Study: How We Cut Page Load Time by 35% (Step-by-Step)
Start with Diagnosis, Not Random Tweaks
Many teams try to fix INP by changing one button handler, memoizing a component, or trimming a few kilobytes from the bundle.
That can help, but it is not the right first move.
The first question is:
where is the slow interaction actually happening?For example:
- during initial page load, before the app is really ready
- after hydration, when a user opens a menu or modal
- inside a form, where validation and state updates feel heavy
- in dashboards, filters, tabs, or tables with lots of client rendering
You need the slow interaction, not just the idea of one.
What Usually Causes Poor INP in Next.js Apps
1. Too much client-side work near the top of the tree
This is one of the most common problems.
A route that could mostly render on the server gets turned into a large client boundary. That means more JavaScript has to download, parse, hydrate, and execute before the page feels truly responsive.
If a route only needs a few interactive islands, keep those islands small.
Everything else should stay as server-rendered as possible.
2. Large client bundles loaded before the user needs them
Next.js documents lazy loading as a way to reduce the amount of JavaScript needed for the initial route.
That matters directly for INP, because less JavaScript usually means less main-thread work competing with user input.
'use client'
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('./heavy-chart'))
export function Dashboard() {
return <HeavyChart />
}The better version is often to load low-frequency UI only when the user actually asks for it:
- advanced filters
- charts below the fold
- modal flows
- WYSIWYG editors
- support widgets
3. Third-party scripts firing too early
A page can look visually ready while third-party scripts are still chewing up the main thread.
This often comes from:
- chat widgets
- heatmaps
- session replay tools
- testing tools
- marketing scripts that do not need first-view priority
Next.js gives you script loading strategies for a reason.
import Script from 'next/script'
export function MarketingScripts() {
return (
<Script
src="https://example.com/chat.js"
strategy="lazyOnload"
/>
)
}If a script does not need to compete with the first interaction, do not let it.
4. Interaction handlers doing too much synchronous work
INP does not only measure the wait before a handler starts.
It also reflects the work done inside the interaction and the time until the next visual update appears.
That means slow INP often comes from handlers that:
- validate too much on every keystroke
- synchronously transform large datasets
- trigger expensive filtering or sorting
- update broad areas of state
- cause large component subtrees to re-render
5. Long tasks during load or interaction
web.dev defines long tasks as tasks that run longer than 50 milliseconds.
If the main thread is busy with long tasks, the browser cannot respond to input quickly.
That is why INP problems often feel like this:
- the user clicks
- nothing seems to happen
- then everything updates at once
The app is not necessarily broken. It is just monopolizing the main thread.
A Practical Workflow to Debug INP in Next.js
1. Confirm the problem in field data
Do not guess from one laptop.
Use:
- Search Console and CrUX signals
- your RUM setup
web-vitalsreporting if you already collect it
You want to know:
- which routes have bad INP
- whether the problem is mobile-heavy
- whether it appears during load, browsing, or form interaction
2. Reproduce the interaction in the lab
Use Chrome DevTools Performance on a mid-range device profile.
Record the exact interaction:
- tapping a mobile menu
- opening a pricing toggle
- typing in a search box
- submitting a form
- switching filters in a dashboard
3. Look for the blocking work
The usual blockers are:
- large script evaluation
- long JavaScript tasks
- expensive rendering
- too much work attached to one interaction
You are not just looking for "the component". You are looking for the biggest chunk of time between user intent and the next visible paint.
4. Fix the most expensive category first
The fix depends on the real bottleneck:
- too much JS: reduce the client bundle
- too much hydration: shrink client boundaries
- too many scripts: defer or remove them
- slow handlers: simplify or split the work
- expensive re-render: localize state and reduce the rendered surface
The Highest-Impact Fixes in Next.js Apps
Keep more UI on the server
If a route does not need client interactivity for most of its structure, keep the route server-heavy and client-light.
This is often the cleanest fix because it cuts JavaScript before it can become an interaction problem.
Lazy load low-frequency client features
Do not load every chart, dialog, editor, and personalization widget on first render just because the route might need it later.
Ship less first. Load more on demand.
Audit script strategy aggressively
A surprising number of INP problems come from non-essential scripts competing with the first serious interaction.
Ask of every third-party script:
- does it need to load before interaction?
- does it need to load on every route?
- does it need to run before the user even understands the page?
If not, defer it.
Simplify interaction work
This is where many app teams leak responsiveness.
Examples:
- validate after a pause instead of on every keystroke
- avoid filtering huge arrays in a click handler
- move low-priority work off the critical interaction path
- keep state closer to the component that actually needs it
Reduce layout and paint cost after input
Some interactions are slow because the visual update is too expensive.
This often happens when:
- one click repaints a huge area
- animations overlap with heavy DOM updates
- accordions or drawers trigger large layout recalculations
The goal is not only to start work sooner. It is to show the result sooner.
What Not to Do
Do not treat INP as only a button problem
Sometimes the button is fine. The page around it is not.
Do not only optimize lab numbers
INP is a field metric. Use lab tools to investigate, but judge success by real-user improvement.
Do not keep every client-side convenience by default
A lot of product teams keep features always loaded because it feels simpler in development. That simplicity often gets paid back as poor responsiveness in production.
A Good Default Priority Order
If you need a practical order, use this:
1. identify the slow interaction from field data 2. shrink unnecessary client boundaries 3. lazy load low-frequency components and libraries 4. defer non-essential third-party scripts 5. simplify heavy interaction handlers 6. re-test the same interaction on mobile-like conditions
That order usually moves the real experience more than isolated micro-optimizations.
Related Reading
- Core Web Vitals for SaaS Landing Pages: What to Fix First
- LCP vs INP: Which Metric Is Hurting Your Conversions?
- How to Build High-Performance React and Next.js Apps
Need Help Finding the Real INP Bottleneck?
If your Next.js app feels loaded but still responds slowly at the moment users try to act, contact me and I can help you audit the route around real interaction bottlenecks instead of generic speed advice.
Final Takeaway
The fastest way to fix INP in Next.js is usually not a clever React trick.
It is reducing how much client-side work competes with user intent.
Find the slow interaction, identify the blocking work, and then cut the JavaScript, scripts, or render cost that sits between the user's action and the next visible response.
Topic Hub
Web Performance / Core Web Vitals
INP, LCP, JavaScript reduction, and performance fixes tied to conversions.
Open Web Performance / Core Web Vitals hubRelated Reading
8 min read
LCP vs INP: Which Metric Is Hurting Your Conversions?
LCP and INP hurt conversions in different ways. This guide shows how to tell whether your main problem is slow first impression or slow interaction, and what to fix first on SaaS and lead-gen pages.
6 min read
Case Study: How We Cut Page Load Time by 35% (Step-by-Step)
From 4.2s to 2.7s load time in 3 days. Here are the exact image optimizations, code splitting techniques, and caching strategies we used.
Site speed only matters if it improves the buyer journey.
I audit Core Web Vitals, interaction lag, and conversion friction together so you know which fixes will actually move revenue and lead quality.
Written by Salman Izhar
Frontend Developer specializing in React, Next.js, and building high-converting web applications.
Learn More