NX

Application integration

# Next.js + Transloadit

Use Uppy in a Client Component and a small App Router endpoint that signs a fixed Transloadit Template without exposing the Auth Secret.

Executable recipe

## Build the integration

The server route signs a fixed Template, and the Client Component gives Uppy the signed params before each upload.

1. Create a Transloadit Template and put its ID, Auth Key, and Auth Secret in server environment variables.
2. Add the Route Handler and protect it with the same authorization checks as the rest of your application.
3. Render the UploadForm Client Component on a page and select a file to run the Template.

### Install

```
yarn add @uppy/core @uppy/dashboard @uppy/react @uppy/transloadit transloadit
```

### app/api/transloadit/route.ts

```
import { NextResponse } from 'next/server'
import { Transloadit } from 'transloadit'

export async function POST() {
  const authKey = process.env.TRANSLOADIT_KEY
  const authSecret = process.env.TRANSLOADIT_SECRET
  const templateId = process.env.TRANSLOADIT_TEMPLATE_ID
  if (!authKey || !authSecret || !templateId) {
    return NextResponse.json({ error: 'Server configuration is incomplete' }, { status: 500 })
  }

  const transloadit = new Transloadit({ authKey, authSecret })
  const { params, signature } = transloadit.calcSignature({ template_id: templateId })
  return NextResponse.json(
    { params, signature },
    { headers: { 'Cache-Control': 'private, no-store' } },
  )
}
```

### app/UploadForm.tsx

```
'use client'

import Uppy from '@uppy/core'
import TransloaditPlugin from '@uppy/transloadit'
import { Dashboard } from '@uppy/react'
import { useEffect, useState } from 'react'

import '@uppy/core/css/style.min.css'
import '@uppy/dashboard/css/style.min.css'

export function UploadForm() {
  const [uppy] = useState(() =>
    new Uppy().use(TransloaditPlugin, {
      waitForEncoding: true,
      async assemblyOptions() {
        const response = await fetch('/api/transloadit', { method: 'POST' })
        if (!response.ok) throw new Error('Could not authorize upload')
        return response.json()
      },
    }),
  )

  useEffect(() => () => uppy.destroy(), [uppy])

  return <Dashboard uppy={uppy} />
}
```

## Authentication

* Keep TRANSLOADIT\_SECRET in an unprefixed server environment variable. Next.js exposes variables prefixed with NEXT\_PUBLIC\_ to browser bundles.
* The Route Handler uses the official Node SDK to sign the fixed Template ID and returns only short-lived params and a signature to the browser.
* Require the user authorization your product needs before returning a signature, and do not accept arbitrary Template IDs or Steps from the browser.

## Limitations and operational notes

* The browser cannot protect an Auth Secret. Signature generation and authorization checks must remain in server-only code.
* waitForEncoding keeps the upload UI waiting for processing. For long jobs, use Assembly notifications or retrieve the Assembly later.
* The example authorizes one fixed Template. Dynamic fields still need server-side validation before they are included in signed params.

## Related Robots

* [/upload/handle](/docs/robots/upload-handle.md)\
  Handle uploads
* [/image/resize](/docs/robots/image-resize.md)\
  Resize images
* [/video/encode](/docs/robots/video-encode.md)\
  Encode video

## Documentation

* [Transloadit Uppy documentation](/docs/sdks/uppy.md)
* [Transloadit authentication documentation](/docs/api/authentication.md)
* [Uppy Next.js integration guide⁠](https://uppy.io/docs/nextjs/)
* [Next.js data security guide⁠](https://nextjs.org/docs/app/guides/data-security)
  [Create a Template](/c/templates/new/)

More integrations

## Continue building your stack

LV

### [Laravel](/integrations/laravel.md)

Create Assemblies from Laravel with the official PHP SDK.

PY

### [Python](/integrations/python.md)

Run signed Assembly jobs with the maintained Python SDK.

RB

### [Ruby](/integrations/ruby.md)

Create and monitor signed Assemblies from Ruby.
