Guide — Upload from Next.js

The APULODI SDK is server-side software. In Next.js the natural home is a route handler (App Router) — the SDK, the API key and the file bytes never touch the browser.

1. Set the environment variable

env
APULODI_API_KEY=apk_test_your_key_here

2. Upload route handler

app/api/uploads/route.ts:

ts
import { NextRequest, NextResponse } from "next/server";
import { Apulodi } from "@apulodi/sdk";

const apulodi = new Apulodi({
  apiKey: process.env.APULODI_API_KEY!,
});

export async function POST(request: NextRequest) {
  const form = await request.formData();
  const file = form.get("file");

  if (!(file instanceof File)) {
    return NextResponse.json({ error: "missing_file" }, { status: 400 });
  }

  const result = await apulodi.files.upload({
    file, // Blob/File — bytes go directly to storage
    fileName: file.name,
    contentType: file.type || "application/octet-stream",
    path: "uploads",
  });

  return NextResponse.json({ id: result.id, filename: result.filename });
}

Why this is safe

The SDK runs inside the route handler on the server. Your APULODI_API_KEY is never serialized into client JavaScript, and file bytes go straight from the handler to storage via the presigned URL.

3. Browser form

html
<form id="upload">
  <input type="file" name="file" />
  <button type="submit">Upload</button>
</form>

<script>
  document.getElementById("upload").addEventListener("submit", async (event) => {
    event.preventDefault();
    const form = new FormData(event.currentTarget);
    await fetch("/api/uploads", { method: "POST", body: form });
  });
</script>

4. Serve a download URL

app/api/files/[id]/download/route.ts:

ts
import { NextRequest, NextResponse } from "next/server";
import { Apulodi } from "@apulodi/sdk";

const apulodi = new Apulodi({ apiKey: process.env.APULODI_API_KEY! });

export async function GET(
  _request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const { id } = await params;
  const { url, expiresAt } = await apulodi.files.downloadUrl(id, {
    expiresInSeconds: 300,
  });
  return NextResponse.json({ url, expiresAt });
}

Your frontend can then fetch() that presigned URL (or point an <img> / <a> at it) to stream the file directly from storage.

What to avoid

  • import { Apulodi } from "@apulodi/sdk" inside Client Components.
  • ❌ Putting the API key in NEXT_PUBLIC_* variables.
  • ❌ Using the SDK directly in the browser (it would need your key).

Next: Guide — Handling large files.