Next.js

You will add an uploader that sends files from the browser straight to MediaLit, then keep the file when the user saves. The full app is in examples/next-app-router.

  1. Install the packages

    npm
    npm install medialit @medialit/react

    medialit runs on your server and holds the API key. @medialit/react is the browser uploader.

  2. Add your API key

    Add the key from your app's settings in the dashboard to .env.local:

    .env.local
    MEDIALIT_API_KEY=your_api_key
    # Only if you self-host MediaLit
    # MEDIALIT_ENDPOINT=https://medialit.example.com
  3. Create the signature route

    The uploader asks this route for a short-lived upload signature, so the API key never reaches the browser.

    app/api/medialit/signature/route.ts
    import { createSignatureHandler } from "medialit";
    import { auth } from "@/auth"; // your app's authentication
    
    export const POST = createSignatureHandler({
        authorize: async () => {
            const session = await auth();
            return !!session;
        },
    });

    Anyone who passes authorize can upload to your MediaLit app. Return false for visitors who are not signed in.

    To put each user's files in their own group, return a group instead of true:

    authorize: async () => {
        const session = await auth();
        return session ? { group: session.user.id } : false;
    },
  4. Add the uploader

    app/profile/avatar-upload.tsx
    "use client";
    
    import { useState } from "react";
    import { MediaLitUploader } from "@medialit/react";
    import "@medialit/react/styles.css";
    import { saveAvatar } from "./actions";
    
    export function AvatarUpload() {
        const [mediaId, setMediaId] = useState<string>();
    
        return (
            <form action={() => mediaId && saveAvatar(mediaId)}>
                <MediaLitUploader
                    signatureEndpoint="/api/medialit/signature"
                    access="public"
                    accept="image/*"
                    maxFileSize={5 * 1024 * 1024}
                    onUploadComplete={(media) => setMediaId(media.mediaId)}
                />
                <button type="submit" disabled={!mediaId}>
                    Save
                </button>
            </form>
        );
    }

    The uploader shows a drop zone, upload progress with a cancel button, and the uploaded file. Read React to change its text, style or behaviour.

  5. Seal the file when the user saves

    The upload is temporary until you seal it. If the user leaves without saving, MediaLit deletes it after 24 hours.

    app/profile/actions.ts
    "use server";
    
    import { MediaLit } from "medialit";
    
    const medialit = new MediaLit();
    
    export async function saveAvatar(mediaId: string) {
        const media = await medialit.seal(mediaId);
        // Save media.mediaId and media.file with the user's profile.
    }

    Sealing a public file gives it its permanent URL, so save the file returned by seal, not the one from the upload.

Show private files

Private files have signed URLs that expire. Store the mediaId and get a fresh URL when you render the page:

app/documents/[id]/page.tsx
import { MediaLit } from "medialit";

const medialit = new MediaLit();

export default async function DocumentPage({
    params,
}: {
    params: Promise<{ id: string }>;
}) {
    const { id } = await params;
    const document = await getDocument(id); // from your database
    const media = await medialit.get(document.mediaId);

    return <a href={media.file}>Download {media.originalFileName}</a>;
}

Delete files

await medialit.delete(mediaId);

Next steps

  • React covers every prop of MediaLitUploader and the useMediaLitUpload hook for your own UI.

  • Node.js SDK lists everything the server SDK can do.

  • How MediaLit works explains sealing, access and groups.