🚀 Script Optimization in Next.js
The Restaurant Kitchen Analogy
Imagine you’re running a busy restaurant kitchen. You have many helpers (scripts) that do different jobs:
- Some helpers MUST be ready before you can serve any food (critical scripts)
- Some helpers can set up their stations while customers wait (interactive scripts)
- Some helpers can prepare ingredients after service starts (lazy scripts)
Next.js Script Optimization is like being the smartest head chef who knows EXACTLY when each helper should arrive!
📦 The next/script Component
What Is It?
Think of next/script as a magic delivery service for your website’s scripts. Instead of just dumping all packages at your door at once, it delivers each one at the perfect time!
Why Not Just Use Regular <script>?
A regular <script> tag is like ordering pizza delivery with no instructions. The delivery person might:
- Block your doorway (block page loading)
- Arrive when you’re in the shower (bad timing)
- Leave the pizza in the rain (poor performance)
The next/script component is like a smart delivery service that knows:
- When you’ll be home
- Where to leave packages
- What order things should arrive
Basic Usage
import Script from 'next/script'
export default function MyPage() {
return (
<>
<Script src="https://example.com/script.js" />
)
}
That’s it! Just import Script from next/script and use it like a regular tag. But the magic is in the strategy.
🎯 Script Loading Strategies
This is where the real power lives! You get to tell Next.js EXACTLY when to load each script.
1. beforeInteractive - The VIP Guest 👑
<Script
src="https://example.com/critical.js"
strategy="beforeInteractive"
/>
When to use: For scripts that MUST run before ANYTHING else.
Real example: Consent management, bot detection, critical polyfills.
Think of it like: The security guard who must be at the door BEFORE any guests arrive.
⚠️ Warning: Only works in _document.js - use sparingly!
2. afterInteractive - The Default Helper 🙋
<Script
src="https://example.com/analytics.js"
strategy="afterInteractive"
/>
When to use: For scripts needed soon after page loads.
Real example: Analytics, tag managers, chat widgets.
Think of it like: The waiter who starts working right after guests sit down.
✅ This is the default strategy - if you don’t specify one, this is what you get!
3. lazyOnload - The Patient Helper 🐢
<Script
src="https://example.com/social-share.js"
strategy="lazyOnload"
/>
When to use: For scripts that can wait until everything else is done.
Real example: Social media buttons, comments, secondary features.
Think of it like: The helper who cleans up AFTER the party ends.
🎉 Best for performance - loads during browser idle time!
4. worker - The Background Ninja 🥷
<Script
src="https://example.com/heavy-task.js"
strategy="worker"
/>
When to use: For heavy scripts that shouldn’t slow down your page.
Real example: Complex calculations, data processing.
Think of it like: A helper working in a completely separate room!
⚠️ Experimental - requires Partytown setup.
🎬 Script Events - Know When Things Happen!
You can run code when scripts load or fail:
<Script
src="https://example.com/analytics.js"
onLoad={() => {
console.log('Script loaded!')
}}
onError={() => {
console.log('Oops! Script failed.')
}}
/>
Available Events:
| Event | When It Fires |
|---|---|
onLoad |
Script finished loading ✅ |
onReady |
Script loaded + every navigation 🔄 |
onError |
Script failed to load ❌ |
📦 The next/third-parties Package
The Problem It Solves
Loading third-party scripts like Google Analytics or YouTube embeds can be tricky. Each has different requirements, and getting the settings wrong can hurt performance.
The Solution
next/third-parties gives you ready-made components for popular services!
npm install @next/third-parties
Google Analytics - Easy Mode!
Before (complicated):
<Script
src={`https://www.googletagmanager.com/gtag/...`}
strategy="afterInteractive"
/>
<Script id="google-analytics">
{`window.dataLayer = ...`}
</Script>
After (simple):
import { GoogleAnalytics } from '@next/third-parties/google'
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
<GoogleAnalytics gaId="G-XXXXXXX" />
</html>
)
}
Google Tag Manager
import { GoogleTagManager } from '@next/third-parties/google'
<GoogleTagManager gtmId="GTM-XXXXXXX" />
YouTube Embed - Performance Boost!
Regular YouTube embeds load lots of JavaScript upfront. The next/third-parties version uses a lightweight placeholder!
import { YouTubeEmbed } from '@next/third-parties/google'
<YouTubeEmbed videoid="dQw4w9WgXcQ" />
Why it’s better:
- Shows a static image first (fast!)
- Only loads video player when user clicks
- Huge performance boost for pages with videos
Google Maps
import { GoogleMapsEmbed } from '@next/third-parties/google'
<GoogleMapsEmbed
apiKey="YOUR_API_KEY"
height={400}
width={600}
mode="place"
q="New York City"
/>
🧠 Quick Decision Guide
graph TD A["Need to load a script?"] --> B{Is it critical?} B -->|Yes| C["beforeInteractive"] B -->|No| D{Needed right away?} D -->|Yes| E["afterInteractive"] D -->|No| F{Heavy processing?} F -->|Yes| G["worker"] F -->|No| H["lazyOnload"]
✨ Pro Tips
Tip 1: Inline Scripts Need an ID
<Script id="my-inline-script">
{`console.log('Hello!')`}
</Script>
Without id, Next.js can’t track the script properly!
Tip 2: Use next/third-parties When Available
If there’s a component for your service, use it! The Next.js team has already optimized it.
Tip 3: Audit Your Scripts
Ask yourself:
- Does this script REALLY need to load early?
- Can this wait until the page is idle?
- Is there a
next/third-partiesversion?
🎯 Summary
| What | How | When |
|---|---|---|
next/script |
Smart script loader | Always for external scripts |
beforeInteractive |
Load before hydration | Critical only |
afterInteractive |
Load after page interactive | Default - analytics, etc. |
lazyOnload |
Load when idle | Non-critical scripts |
worker |
Load in web worker | Heavy processing |
next/third-parties |
Pre-built components | Google services, etc. |
Remember: The best script is the one that loads at the perfect time - not too early, not too late, but just right! 🎯
