惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
博客园 - 司徒正美
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
Y
Y Combinator Blog
博客园 - 聂微东
M
MIT News - Artificial intelligence
博客园_首页
Jina AI
Jina AI
博客园 - 叶小钗
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
Vercel News
Vercel News
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
N
Netflix TechBlog - Medium
B
Blog
Google DeepMind News
Google DeepMind News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

ImageKit.io Blog

Next.js Image Optimization with ImageKit Use Video as a Background in Your Next.js Project How to Fix Autoplay Video in Next.js How Durian Scaled a Visual-First Retail Experience to 350K Monthly Visitors Online How Matsmart accelerated image delivery across countries with ImageKit AI in Digital Asset Management: From Smart Workflows to Agentic Automation How Joseph Joseph unified and secured global video delivery with ImageKit How Modall powers fast, effortless media delivery across 40+ projects with ImageKit Digital Asset Management (DAM) Trends: 2026 Report How to add a poster image to Video.js player (and automate it) HLS streaming with Video.js + React Building the future of storytelling with fast, AI-powered video delivery How PushOwl delivers 100M+ image-rich notifications seamlessly with ImageKit How Homify delivers millions of interior design images seamlessly with ImageKit Better event discovery with lightning‑fast videos & images Adding video player in React Native Video player in Angular applications Crop and resize videos in React Next.js image and video upload React image and video upload React video optimization How we quadrupled our traffic to 625K monthly page views How Apollo 24|7 boosted performance & reduced costs with ImageKit Simplify your media workflows with ImageKit DAM integrations Extending Lighthouse for custom image and video optimization analysis Brand Asset Management: What is it? How does it work? WordPress Digital Asset Management Guide - Manage your WP media assets better Why Shopify retailers need a digital asset management solution DAM vs. SharePoint: Which is best for you? AI-powered Metadata and Tagging in Digital Asset Management
The Complete Guide to Video Optimization in Next.js
Angel Pichardo · 2026-04-19 · via ImageKit.io Blog

Next.js optimizes images automatically with next/image. Video, however, doesn't get the same built-in optimization treatment. There is no next/video, and no native support for compression, format negotiation, or adaptive streaming.

This guide walks through a complete video optimization pipeline in Next.js, covering format conversion, compression, resizing, lazy loading with scroll-aware playback, and adaptive bitrate streaming.

We'll implement all of this using ImageKit's real-time video processing API via its easy-to-use Next.js SDK. So there's no separate processing pipeline or build step required.

What we'll cover:

  1. Setting up the ImageKit Next.js SDK.
  2. Resizing, compressing, and converting video formats.
  3. Generating poster images and lazy loading for better Core Web Vitals.
  4. Adaptive bitrate streaming with HLS for bandwidth-aware delivery.

Setting up the ImageKit SDK

Install the package:

npm install @imagekit/next

Wrap your root layout with ImageKitProvider:

// app/layout.tsx
import { ImageKitProvider } from '@imagekit/next';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <ImageKitProvider urlEndpoint={process.env.NEXT_PUBLIC_IMAGEKIT_URL_ENDPOINT!}>
          {children}
        </ImageKitProvider>
      </body>
    </html>
  );
}

Add your URL endpoint to .env.local:

NEXT_PUBLIC_IMAGEKIT_URL_ENDPOINT=https://ik.imagekit.io/ikmedia

Import the Video component from the SDK wherever you need it:

import { Video } from '@imagekit/next';

The Video component is a lightweight wrapper around the HTML <video> element. It supports all standard HTML video attributes (autoPlay, muted, loop, controls, poster, preload, playsInline, and more) plus ImageKit-specific props: urlEndpoint, transformation, transformationPosition, and queryParameters.

Resize to match your viewport

The single biggest optimization is serving video at the size you actually display it. A 4K source video rendered in a 1280px container wastes bandwidth on pixels nobody sees.

Add a width to the transformation prop to resize server-side before delivery:

<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280 }]}
  autoPlay
  muted
  playsInline
  loop
  preload="none"
  className="w-full h-full object-cover"
/>

ImageKit maintains the aspect ratio automatically when you specify only width. The original stays untouched in your media library.

The difference is dramatic:

MetricOriginal (4K)Resized (1280px)Improvement
File Size63.76 MB3.2 MB95% smaller
Load Time (4G)5.3s420ms92% faster

When you specify both width and height, the default crop mode is maintain_ratio, which crops from all sides to preserve the aspect ratio. If you want the full video to remain visible without any cropping, specify a different crop strategy:

// Preserves the full video, may resize one dimension to maintain aspect ratio
<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280, height: 720, crop: 'at_max' }]}
/>

// Preserves the full video by adding padding to match exact dimensions
<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280, height: 720, cropMode: 'pad_resize' }]}
/>

Note: The crop parameter controls the basic resize strategy (maintain_ratio, force, at_max, at_least), while cropMode controls the crop method (extract, pad_resize). See the video resize and crop docs for the full list of options.

Format, quality, and audio

Three more optimizations that stack on top of resizing.

Automatic format conversion

ImageKit automatically delivers the most efficient video format based on browser support. Browsers like Chrome receive VP9/WebM for better compression, while Safari gets H.264/MP4. The transformation happens server-side - your URL stays the same, no <source> tag juggling required.

Open DevTools and check the Content-Type response header on any ImageKit video request. You'll see video/webm in Chrome even though the URL ends in .mp4. This automatic format negotiation ensures optimal file size without additional code.

Quality control

ImageKit compresses video automatically. The default quality setting is configurable in your dashboard settings. Override it per-URL when you need more control:

// Higher quality for product videos
<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280, quality: 80 }]}
/>

// Lower quality for ambient backgrounds
<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280, quality: 40 }]}
/>

For most use cases, the default works well. Adjust only when visual fidelity matters (product demos) or when file size is critical (mobile hero backgrounds).

Strip audio for decorative videos

Muted videos still carry an audio track. Stripping it saves 10-30% of the file size:

<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280, audioCodec: 'none' }]}
  autoPlay
  muted
  loop
  playsInline
/>

Use audioCodec: 'none' on any video where audio will never play: hero backgrounds, ambient loops, decorative sections.

Common video transformations

Here are the most useful video transformation options. For the complete list, see the Next.js SDK supported transformations reference.

SDK PropertyURL ParameterWhat it does
widthwResize to specified width in pixels
heighthResize to specified height in pixels
qualityqSet output quality (1-100)
audioCodecacSet audio codec (none strips audio)
videoCodecvcSet video codec (e.g., h264)
startOffsetsoStart the video at a specific timestamp (in seconds)
endOffseteoEnd the video at a specific timestamp (in seconds)
durationduLimit the video duration (in seconds)
cropcCrop strategy (maintain_ratio, force, at_max, at_least)
cropModecmCrop method (pad_resize, extract)
focusfoFocus point for cropping (e.g., center, top, left)
streamingResolutionssrResolutions for adaptive bitrate streaming (e.g., 240_360_480_720)

These properties can be combined in a single transformation object. For the full reference, see the Next.js SDK docs.

Generate poster images

A poster image prevents the black flash before a video loads. Since Chrome 116, poster images are also LCP candidates, which means they directly affect your Largest Contentful Paint score.

ImageKit generates a thumbnail from any video by appending /ik-thumbnail.jpg to the path:

https://ik.imagekit.io/ikmedia/docs_images/examples/Videos/example_video_2.mp4/ik-thumbnail.jpg

By default this extracts the first frame. Use the startOffset parameter to pick a specific timestamp, typically past any black opening frames.

In the SDK, use buildSrc to generate the poster URL alongside your video:

import { Video, buildSrc } from '@imagekit/next';

const urlEndpoint = process.env.NEXT_PUBLIC_IMAGEKIT_URL_ENDPOINT!;

const poster = buildSrc({
  urlEndpoint,
  src: '/docs_images/examples/Videos/example_video_2.mp4/ik-thumbnail.jpg',
  transformation: [{ width: 1280, startOffset: 3 }],
});

<Video
  src="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 1280 }]}
  poster={poster}
  preload="none"
  autoPlay
  muted
  playsInline
  loop
  className="w-full"
/>

ℹ️

The thumbnail URL is a regular ImageKit image URL. You can apply image transformations to it: resize, convert to WebP, add blur for a placeholder. See the thumbnail docs for all options.

For above-the-fold videos, preload the poster to improve LCP:

// In your page's <head>
<link rel="preload" as="image" href={poster} fetchPriority="high" />

A poster image loads in ~100-200ms. A video's first frame can take seconds.

Lazy load below-fold video

Loading six videos on page mount defeats every optimization above. Use the right preload strategy and load below-fold videos on scroll.

Preload strategies

ValueWhat downloadsBest for
preload="none"Nothing until playBelow-fold videos with poster images
preload="metadata"Duration, dimensions, first frameAbove-fold user-initiated videos
preload="auto"Entire file (browser decides)Critical autoplay hero videos only

ℹ️

Mobile browsers often ignore preload="auto" to save bandwidth. Don't rely on it for critical playback.

Load on scroll with Intersection Observer

This component renders a poster image initially, then swaps to the full Video component when it enters the viewport:

// components/LazyVideo.tsx
'use client';

import { useState } from 'react';
import { Video, buildSrc } from '@imagekit/next';
import { useInView } from 'react-intersection-observer';

interface LazyVideoProps {
  path: string;
  transformation?: Array<Record<string, string | number>>;
  className?: string;
}

export function LazyVideo({
  path,
  transformation = [{ width: 1280 }],
  className = '',
}: LazyVideoProps) {
  const urlEndpoint = process.env.NEXT_PUBLIC_IMAGEKIT_URL_ENDPOINT!;
  const [hasEntered, setHasEntered] = useState(false);

  const { ref } = useInView({
    triggerOnce: true,
    rootMargin: '200px',
    onChange: (inView) => {
      if (inView) setHasEntered(true);
    },
  });

  const poster = buildSrc({
    urlEndpoint,
    src: `${path}/ik-thumbnail.jpg`,
    transformation: [{ width: 1280 }],
  });

  return (
    <div ref={ref} className={className}>
      {hasEntered ? (
        <Video
          src={path}
          transformation={transformation}
          poster={poster}
          preload="metadata"
          controls
          playsInline
          className="h-full w-full object-cover"
        />
      ) : (
        <img
          src={poster}
          alt=""
          className="h-full w-full object-cover"
        />
      )}
    </div>
  );
}

Usage:

<LazyVideo
  path="/docs_images/examples/Videos/example_video_2.mp4"
  transformation={[{ width: 800 }]}
  className="aspect-video"
/>

The rootMargin: '200px' starts loading 200px before the component enters the viewport, giving the video a head start.

Adaptive bitrate streaming with HLS

A single MP4 file serves the same quality to a phone on 3G and a desktop on fiber. Adaptive bitrate streaming solves this by generating multiple quality tiers and letting the player switch between them based on network conditions.

Generate an HLS manifest with one URL

Append /ik-master.m3u8 to any video path and specify the resolutions you want:

https://ik.imagekit.io/ikmedia/docs_images/examples/Videos/example_video_2.mp4/ik-master.m3u8?tr=sr-240_360_480_720_1080

ImageKit generates all resolution variants and caches them. Available tiers:

ResolutionMax BitrateOutput
240p200K426x240
360p400K640x360
480p800K854x480
720p3300K1280x720
1080p5500K1920x1080

All variants use H.264 video and AAC audio.

First-request behavior

The first time you request an HLS manifest, ImageKit returns a 202 status with an empty body while it generates the variants. This can take seconds to minutes depending on video length and resolution count.

For production, request your manifest URLs once before going live, or use post-upload transformations to generate them eagerly on upload. You can listen for video webhook events (video.transformation.ready) to know when all variants are encoded.

Playing HLS in Next.js

Safari plays .m3u8 natively. Chrome, Firefox, and Edge need a JavaScript player to handle the manifest and segment loading. You have two good options.

The official @imagekit/video-player package handles HLS, adaptive bitrate streaming, quality switching, and cross-browser compatibility out of the box. It also includes built-in support for AI-generated subtitles, chapters, playlists, and shoppable videos. Check the official documentation for the latest features and updates.

Install the package:

npm install @imagekit/video-player

Then drop in the React component:

'use client';

import { IKVideoPlayer } from '@imagekit/video-player/react';
import '@imagekit/video-player/styles.css';

export default function VideoPlayer() {
  const ikOptions = {
    imagekitId: 'your_imagekit_id',
    abs: {
      protocol: 'hls',
      sr: [360, 480, 720, 1080],
    },
  };

  const source = {
    src: 'https://ik.imagekit.io/your_imagekit_id/hero.mp4',
  };

  return <IKVideoPlayer ikOptions={ikOptions} source={source} />;
}

That's the entire setup. The abs configuration tells the player to generate HLS variants at 360p, 480p, 720p, and 1080p, then handles quality switching automatically based on network conditions. You also get a quality selector in the player UI, seek thumbnails on the progress bar, and an optional floating mode when the player scrolls out of view.

Option 2: Video.js with VHS plugin

If you need a custom implementation and want full control over the player implementation, Video.js with the VHS (Video HTTP Streaming) plugin is an excellent choice. It provides robust HLS playback across all browsers with extensive customization options. For a complete implementation guide, see HLS streaming with Video.js and ImageKit.

Conclusion

Next.js gives you next/image for images but leaves video to you. Here is the optimization checklist:

  1. Resize to match the largest display size. Don't serve 4K to a 720px container.
  2. Let ImageKit auto-negotiate format. WebM for Chrome, MP4 for Safari.
  3. Strip audio with audioCodec: 'none' on any video without meaningful sound.
  4. Add a poster image and preload it for above-fold videos.
  5. Lazy load every below-fold video with Intersection Observer.
  6. Use HLS for long-form content where network conditions vary.

Upload once. ImageKit handles compression, format conversion, and CDN delivery.

Sign up for a free ImageKit account and try the width: 1280, audioCodec: 'none' transformation on your own video.