I'm trying to convert a WebM video file to MP4 using fluent-ffmpeg and @ffmpeg-installer/ffmpeg in a Next.js 14 API route (using the App Router). The same code worked perfectly in a standalone Node.js script, but when moved to Next.js, I get an error during runtime.
import { NextRequest, NextResponse } from "next/server";
import { getSession } from "@/lib/session";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import ffmpeg from "fluent-ffmpeg";
import ffmpegInstaller from "@ffmpeg-installer/ffmpeg";
import { writeFile, unlink, mkdir, readFile } from "fs/promises";
import { existsSync } from "fs";
import path from "path";
import { tmpdir } from "os";
const s3Client = new S3Client({
region: process.env.AWS_REGION!,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
}
});
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
export async function POST(request: NextRequest) {
try {
const user = await getSession();
if (!user) {
return NextResponse.json(
{ success: false, message: "Unauthorized" },
{ status: 401 }
);
}
const formData = await request.formData();
const file = formData.get("file") as File;
if (!file) {
return NextResponse.json(
{ success: false, message: "No file found" },
{ status: 400 }
);
}
const tempDir = path.join(tmpdir(), "video-conversion");
if (!existsSync(tempDir)) {
await mkdir(tempDir, { recursive: true });
}
const inputPath = path.join(tempDir, `${Date.now()}-input.webm`);
const outputPath = path.join(tempDir, `${Date.now()}-output.mp4`);
// Write uploaded file to disk
const buffer = Buffer.from(await file.arrayBuffer());
await writeFile(inputPath, buffer);
// Convert video using ffmpeg
await new Promise<void>((resolve, reject) => {
ffmpeg(inputPath)
.outputOptions(["-c:v libx264", "-preset fast", "-crf 23", "-r 30"])
.toFormat("mp4")
.on("end", () => resolve())
.on("error", err => reject(err))
.save(outputPath);
});
// Upload to S3
const key = `${user.id}/${Date.now()}.mp4`;
const convertedBuffer = await readFile(outputPath);
await s3Client.send(
new PutObjectCommand({
Bucket: process.env.AWS_S3_BUCKET!,
Key: key,
Body: convertedBuffer,
ContentType: "video/mp4"
})
);
// Cleanup temp files
await Promise.all([
unlink(inputPath).catch(() => {}),
unlink(outputPath).catch(() => {})
]);
return new NextResponse(convertedBuffer, {
headers: {
"Content-Type": "video/mp4",
"Content-Length": convertedBuffer.length.toString()
}
});
} catch (error) {
console.error("Video conversion failed:", error);
return NextResponse.json(
{ success: false, message: "Video conversion failed" },
{ status: 500 }
);
}
}
It worked when I was doing it in node js however when I tried to convert it to next I get the following error:
⨯ ./node_modules/@ffmpeg-installer/ffmpeg
Module not found: Can't resolve './ROOT/node_modules/@ffmpeg-installer/ffmpeg/node_modules/@ffmpeg-installer/win32-x64/package.json'
server relative imports are not implemented yet. Please try an import relative to the file you are importing from.
Questions Why does @ffmpeg-installer/ffmpeg fail with this import resolution error in Next.js?
Any help or workaround would be greatly appreciated!
Node version: v22.21.0
"next": "15.2.4",
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"fluent-ffmpeg": "^2.1.3",
I am using turbopack and I am using npm version 10.9.4
npm whyoryarn why) - Whether you're using turbopack or not - Package manager (npm, yarn, bun, pnpm) - Operating system - Whether This looks like it's a bundler error that might be because of theexportsfield or something similar, but it's hard to be sure from just the code and the error.