This example demonstrates how to use Workflow DevKit with Express and Vercel Sandbox to build an audio compression service. Audio files are uploaded via multipart/form-data, processed by FFmpeg within a durable workflow running in an isolated sandbox, and streamed directly back in the HTTP response.
- Sandbox isolation: FFmpeg runs in a Vercel Sandbox for secure, isolated processing
- Workflow orchestration: Audio compression is broken into multiple steps (
createSandbox->setupFfmpeg->transcode->streamOutput->stopSandbox) - Streaming support: Results are streamed back to the client as they're produced
- FFmpeg compression: Converts audio to AAC codec in M4A container at 128kbps
VERCEL_OIDC_TOKEN: The workflow runtime expects theVERCEL_OIDC_TOKENenvironment variable to be present for@vercel/sandbox. When running inside a Vercel Sandbox this is injected automatically; if you run the server outside of Vercel, you must provide a valid OIDC token yourself.
-
Clone this example and install dependencies:
git clone https://github.com/vercel/workflow-examples cd workflow-examples/ffmpeg-processing pnpm install -
Link your Vercel project:
npx vercel link
-
Fetch the
VERCEL_OIDC_TOKEN:npx vercel env pull
-
Start the development server:
pnpm dev
-
Test the audio compression workflow:
# Convert a WAV file to compressed M4A curl -X POST -F "file=@input.wav;type=audio/wav" -H "Expect:" http://localhost:3000/convert --output output.m4a
The endpoint accepts any audio file and returns a compressed M4A file. Be sure to update the audio file extension if not a .wav file.
Compresses an uploaded audio file using FFmpeg within a workflow.
Request:
- Content-Type:
multipart/form-data - Field name:
file - Accepted formats: WAV, MP3, OGG, FLAC, AAC, M4A
Response:
- Content-Type:
audio/mp4 - Body: Compressed audio file (M4A/AAC at 128kbps)
Example:
curl -X POST -F "file=@podcast.wav;type=audio/wav" -H "Expect:" http://localhost:3000/convert --output podcast.m4a- Express route receives the upload via
multer.memoryStorage() - Workflow orchestrates five steps:
createSandbox: Provisions a Vercel Sandbox instancesetupFfmpeg: Downloads and installs FFmpeg in the sandboxtranscode: Writes input to sandbox, runs FFmpeg to compress audiostreamOutput: Streams the compressed file back to the workflowstopSandbox: Cleans up the sandbox instance
- Response streams the compressed bytes directly to the client
ffmpeg-processing/
├── src/
│ ├── index.ts # Express app with /convert route
│ └── workflows/
│ └── audio-convert/
│ ├── index.ts # Main workflow orchestration
│ └── steps/ # Individual workflow steps
│ ├── create-sandbox.ts
│ ├── setup-ffmpeg.ts
│ ├── transcode.ts
│ ├── stream-output.ts
│ └── stop-sandbox.ts
├── nitro.config.ts # Nitro configuration with workflow module
├── package.json
├── tsconfig.json
└── README.md