Integration Recipes

Next.js App Router Integration

How to integrate `@cloudizero/sdk` with Next.js 14, 15, and 16 using React Server Actions and Client Components.

Server Action Upload Pattern

Using Server Actions keeps your master API key completely secure on the server while offering a clean, type-safe API for client forms:

app/actions/upload.ts
// app/actions/upload.ts
"use server";

import { Cloudizero } from "@cloudizero/sdk";

const cz = new Cloudizero({
  apiKey: process.env.CLOUDIZERO_API_KEY!,
});

export async function uploadAvatar(formData: FormData) {
  const file = formData.get("avatar") as File;
  if (!file) throw new Error("No file provided");

  const buffer = Buffer.from(await file.arrayBuffer());

  const asset = await cz.storage.upload({
    file: buffer,
    fileName: file.name,
    projectId: process.env.CLOUDIZERO_PROJECT_ID!,
    mimeType: file.type,
  });

  return { success: true, url: asset.url };
}

Client Form Component

Consuming the server action inside a React 19 Client Component:

app/components/avatar-uploader.tsx
// app/components/avatar-uploader.tsx
"use client";

import { useTransition } from "react";
import { uploadAvatar } from "@/app/actions/upload";

export function AvatarUploader() {
  const [isPending, startTransition] = useTransition();

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);

    startTransition(async () => {
      const res = await uploadAvatar(formData);
      alert("Uploaded! " + res.url);
    });
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <input type="file" name="avatar" required />
      <button
        type="submit"
        disabled={isPending}
        className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"
      >
        {isPending ? "Uploading..." : "Upload Avatar"}
      </button>
    </form>
  );
}