Llinuxctrl
Full Integration Guide

Using grabr with Next.js

Because grabr writes directly to the filesystem and performs high-speed parallel network requests, it is designed to run in server environments (Node.js or Bun). You cannot run grabr directly inside a browser component.

In this tutorial, we will integrate grabr into a Next.js App Router project using a Server Action to trigger a backend download when a user clicks a button.

1. Create a Next.js Project

Start by initializing a fresh Next.js app and installing grabr.

npx create-next-app@latest my-grabr-app
cd my-grabr-app
npm install @linuxctrl/grabr

2. Build the Server Action

We need a secure backend environment to run grabr. We'll create a Next.js Server Action that instantiates the downloader, adds a job, and starts the transfer.

Create a file at src/app/actions.ts:

"use server";

import { Downloader } from "@linuxctrl/grabr";
import path from "path";
import fs from "fs";

export async function triggerDownload(url: string, filename: string) {
  const outputDir = path.join(process.cwd(), "downloads");
  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }

  const downloader = new Downloader();
  await downloader.start();

  try {
    const job = await downloader.addJob(url, {
      outputDir,
      filename,
      chunks: 8,
    });

    console.log(`Started downloading ${job.filename} (ID: ${job.id})`);
    return { success: true, jobId: job.id };
  } catch (error) {
    console.error("Download failed to start:", error);
    return { success: false, error: String(error) };
  }
}

3. Create the Frontend UI

Now we'll build a simple client component where the user can enter a URL and click a button to tell the server to fetch it using grabr.

Open src/app/page.tsx and replace its contents:

"use client";

import { useState } from "react";
import { triggerDownload } from "./actions";

export default function HomePage() {
  const [url, setUrl] = useState("https://speed.hetzner.de/100MB.bin");
  const [status, setStatus] = useState("");

  const handleDownload = async () => {
    setStatus("Starting grabr engine...");
    const result = await triggerDownload(url, "test-file.bin");

    if (result.success) {
      setStatus(`Downloading! Check your terminal and the ./downloads folder.`);
    } else {
      setStatus(`Error: ${result.error}`);
    }
  };

  return (
    <main className="p-10 max-w-xl mx-auto space-y-4">
      <h1 className="text-2xl font-bold">Grabr Next.js Demo</h1>
      <input
        type="text"
        value={url}
        onChange={(e) => setUrl(e.target.value)}
        className="w-full p-2 border rounded text-black"
        placeholder="Enter file URL..."
      />
      <button
        onClick={handleDownload}
        className="px-4 py-2 bg-cyan-500 text-white font-bold rounded"
      >
        Download on Server
      </button>
      {status && <p className="text-sm font-medium mt-4">{status}</p>}
    </main>
  );
}

4. Run the Application

Start your development server:

npm run dev

Open your browser, click "Download on Server", and watch your server terminal! grabr will instantly parallel-chunk the file directly to your Next.js server's ./downloads folder at maximum speed.

Pro Tip: Progress Streaming

In a full production app, you can use grabr's built-in EventEmitter or WebSocket capabilities to stream live download progress (speeds and ETAs) from the Node.js server back to the React frontend using Server-Sent Events (SSE) or Socket.io!