Products
Products
Video Hosting
Upload and manage your videos in a centralized video library.
Image Hosting
Upload and manage all your images in a centralized library.
Galleries
Choose from 100+templates to showcase your media in style.
Video Messaging
Record, and send personalized video messages.
CincoTube
Create your own community video hub your team, students or fans.
Pages
Create dedicated webpages to share your videos and images.
Live
Create dedicated webpages to share your videos and images.
For Developers
Video API
Build a unique video experience.
DeepUploader
Collect and store user content from anywhere with our file uploader.
Solutions
Solutions
Enterprise
Supercharge your business with secure, internal communication.
Townhall
Webinars
Team Collaboration
Learning & Development
Creative Professionals
Get creative with a built in-suite of editing and marketing tools.
eCommerce
Boost sales with interactive video and easy-embedding.
Townhall
Webinars
Team Collaboration
Learning & Development
eLearning & Training
Host and share course materials in a centralized portal.
Sales & Marketing
Attract, engage and convert with interactive tools and analytics.
"Cincopa helped my Enterprise organization collaborate better through video."
Book a Demo
Resources
Resources
Blog
Learn about the latest industry trends, tips & tricks.
Help Centre
Get access to help articles FAQs, and all things Cincopa.
Partners
Check out our valued list of partners.
Product Updates
Stay up-to-date with our latest greatest features.
Ebooks, Guides & More
Customer Stories
Hear how we've helped businesses succeed.
Boost Campaign Performance Through Video
Discover how to boost your next campaign by using video.
Download Now
Pricing
Watch a Demo
Demo
Login
Start Free Trial
Rendering videos programmatically (for example, using a library like Remotion ) typically involves heavy computation, large binaries (like Chrome for a headless browser), and extended processing time. If you are deploying a Next.js application on Vercel , you might wonder if you can generate videos on the fly using Vercel’s Serverless Functions. In this article, we’ll explore why directly rendering videos within a Vercel Serverless Function is impractical and outline a solution to achieve video rendering by triggering an external renderer . Background & Limitations Vercel Serverless Functions (the standard Node.js lambdas, not Edge Functions) have certain constraints that make direct video rendering difficult: Bundle Size Limit Vercel imposes a 50 MB limit (uncompressed ~250 MB) on serverless function code packages. Unfortunately, Remotion’s rendering stack requires bundling a headless Chromium browser and FFmpeg, totaling around 150 MB or more, which far exceeds this limit. In fact, Chromium alone would nearly fill the entire quota. This means you cannot even upload a function to Vercel that contains all the necessary binaries. Memory and CPU Constraints Video rendering is memory-intensive and CPU-intensive. Remotion’s docs note that it “ works best with 2 GB+ of RAM ”. While Vercel’s functions can provide up to 2 GB of memory on Pro plans, running a headless browser and encoding video frames will push these limits. The CPU time in a serverless function is also limited (default execution timeout is often around 10 seconds on Hobby, extendable up to 60-900 seconds on higher plans). A complex video could easily take longer than that to render, making timeouts a risk. No Native Headless Browser Environment Remotion uses Puppeteer (or a similar headless Chromium) under the hood for rendering React components to video frames. Vercel’s serverless environment does not include a headless browser by default, and including one bumps into the size limit as mentioned. Additionally, writing numerous frames to disk might be problematic - while Vercel functions have ephemeral storage (in /tmp ), it’s limited in size and only persists during the execution. Due to these limitations, it is not feasible to render videos or even still frames directly inside a Vercel Serverless Function . If you attempt to import @remotion/renderer and Chromium in an API route, the deployment will fail, or the function will run out of resources. Recommended Approach: Triggering External Renderers The good news is we can still use Vercel as part of a video-generation workflow - by using it to trigger an external rendering service rather than doing the rendering on Vercel itself. The recommended solution (as also suggested by the Remotion team) is to offload the actual rendering to Remotion Lambda on AWS. Remotion Lambda is a distributed video renderer that runs on AWS Lambda. Instead of a single serverless function doing all the work, Remotion Lambda orchestrates multiple Lambda functions to split the rendering of video frames in parallel, then stitches the final video together in an S3 bucket. You only pay for the time those Lambdas run, and they can scale out to render videos much faster than a single process could. This approach bypasses Vercel’s constraints because all the heavy lifting happens in AWS’s infrastructure, which is designed to handle such tasks. The Vercel function’s job becomes just to call an AWS Lambda function and initiate the process. Implementation Steps To implement video rendering via a Vercel Serverless Function by leveraging Remotion Lambda, follow these high-level steps: 1. Set Up Your Remotion Project and AWS Credentials First, ensure you have a Remotion project (i.e., your video compositions defined in React). Step 1 : Install the Remotion Lambda package in your project (npm i @remotion/lambda ), which provides the tools to deploy and trigger renders. Step 2 : Set up an AWS account and create the necessary IAM role, policy, and user for Remotion Lambda. The Remotion docs provide a detailed guide for this setup (creating a remotion-lambda-policy, a remotion-lambda-role, and an IAM user with access keys). Once you have an AWS Access Key ID and Secret Key for the IAM user, configure them as environment variables in your development and Vercel environment. This way, the Remotion Lambda client will pick up your credentials without conflict. Also set REMOTION_AWS_REGION to your desired AWS region (e.g., us-east-1) if needed. 2. Deploy the Remotion Lambda Function and Site With credentials in place, the next step is to deploy your Remotion project to AWS Lambda. This involves two things: deploying a Lambda function (the renderer) and deploying your video code as a site to S3. Remotion’s CLI makes this fairly straightforward. You can run: npx remotion lambda functions deploy --memory=2048 to create the AWS Lambda function (with a given memory, say 2048 MB). And then deploy your Remotion project code using: npx remotion lambda sites create src/index.ts --site-name=my-video Here, src/index.ts (or your entry file) is where registerRoot() is called in your Remotion project, and --site-name gives a name to your deployment. After running the site deployment, the CLI will output a “serve URL” - a URL to the static bundle of your video project on S3. This URL is crucial: it’s what the Lambda function will open in a headless browser to render the video. Take note of the Lambda function name (from the deploy step) and the serve URL . You might configure these in your application (e.g., as environment variables in Vercel) so that your code knows where to send render requests. Tip: You typically only need to deploy the function once (unless you update Remotion’s version or need to change memory/timeout settings) and redeploy the site whenever you update your video composition code. 3. Create a Vercel API Route to Trigger the Render Now we move to the Vercel side. Create an API endpoint (e.g., pages/api/render-video.ts in a Next.js app) that will receive requests (perhaps with parameters like which video composition to render, and any props for that video) and invoke the Remotion Lambda. Inside this handler, use the Remotion Lambda client to call the render. For example, using Node.js/TypeScript : // pages/api/render-video.ts import { renderMediaOnLambda } from '@remotion/lambda/client'; // use the client import import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const compositionId = req.body.composition; // e.g., 'HelloWorld' const inputProps = req.body.inputProps || {}; // props for the Remotion video, if any try { const { renderId, bucketName } = await renderMediaOnLambda({ region: process.env.REMOTION_AWS_REGION, // e.g., 'us-east-1' functionName: process.env.REMOTION_FUNCTION_NAME!, // your deployed Lambda name serveUrl: process.env.REMOTION_SERVE_URL!, // the Serve URL from deployment composition: compositionId, inputProps, codec: 'h264', // video codec (h264 for MP4 output) imageFormat: 'jpeg', // use JPEG for faster rendering (no transparency needed) privacy: 'public', // make output public (so we can download from S3) // You can include other options like quality, audioCodec, etc., as needed }); // Successfully started the render return res.status(200).json({ status: 'started', renderId, bucketName }); } catch (err: any) { console.error('Render trigger failed:', err); return res.status(500).json({ error: err.message }); } } Let’s break down what’s happening here. We call renderMediaOnLambda() with the AWS region, the Lambda function name, and the server URL, plus the composition ID we want to render. This is an asynchronous call that kicks off the rendering process on AWS Lambda. The function returns immediately with a renderId and bucketName if the render was initiated successfully. We send those back to the client (or caller) as a response, indicating that the render has started. Important Implementation Notes : We imported renderMediaOnLambda from @remotion/lambda/client. This is intentional - the /client import is a “light” version of the library. Remotion documentation advises doing this when calling from serverless functions to avoid bundling unnecessary parts (like the entire AWS SDK or CLI code). Using the client subset keeps our Vercel function package small. The renderMediaOnLambda call needs AWS credentials to work. The Remotion Lambda package will automatically use the REMOTION_AWS_ACCESS_KEY_ID and related env vars we set up earlier to authenticate to AWS. Make sure those are configured in your Vercel project’s Environment Variables settings. We set privacy: 'public' in this example so that the output video file in S3 will be publicly accessible via a URL (this is the default behavior as well). This way, once the render is done, we (or the client) can directly download the video by its S3 URL. If you prefer to keep it private, you can set 'private' and later generate a signed URL, but that adds complexity. 4. Track Progress and Retrieve the Video After step 3, the user (or calling client) has a renderId that identifies the rendering job. The actual rendering happens asynchronously on AWS. The final video won’t be immediately available; it might take several seconds or a couple of minutes, depending on the video length and complexity. We need a way to know when it’s done (and if it succeeded). There are two common strategies to handle this in a Vercel app: Polling: The client can periodically call another API endpoint (or the same one) to check the status of the render. Remotion provides a function getRenderProgress() for this purpose. It takes the renderId, bucketName, region, and functionName and returns the render status, including whether it’s done and the output URL if finished. You could create an endpoint like pages/api/render-status.ts that accepts a renderId and uses getRenderProgress to return the progress. The client (front-end) could poll this every few seconds. For example: import { getRenderProgress } from '@remotion/lambda/client'; // ... const progress = await getRenderProgress({ renderId, bucketName, functionName: process.env.REMOTION_FUNCTION_NAME!, region: process.env.REMOTION_AWS_REGION }); // progress.done will be true if finished, and progress.outputFile will contain the URL When progress.done === true , the progress.outputFile field will contain a direct URL to the rendered video file in S3. You can then return that to the client or perhaps redirect the user to that URL. (If privacy was set to 'public', this URL will be accessible; if not, you’d need to call presignUrl() to get a temporary download link.) Webhook/callback: Alternatively, Remotion Lambda can notify you when the render is complete. You can provide a webhook URL in the renderMediaOnLambda options (and a secret) so that once the video is rendered, Remotion will POST the result to your webhook endpoint. For instance, you might set webhook: { url: 'https://your-app.vercel.app/api/render-webhook', secret: 'someSecret' } in the render call. Then implement a render-webhook API route to verify the signature and mark the video as ready (perhaps update a database or send a notification). This method is more complex to set up, but it avoids continuous polling. For simplicity , polling is easier to understand, but for production with many renders, a webhook might be more efficient. Either way, the final step is obtaining the output video URL . With getRenderProgress, once done is true, you’ll get a URL in the response that points to the video file in S3.For example, something like https://remotionlambda-[...].s3.amazonaws.com/renders/
/out.mp4) . You can then use this URL to download or stream the video for the user. Finally , remember to handle errors: if progress.fatalErrorEncountered is true or the errors array is non-empty, the rendering failed for some reason (maybe invalid props or an issue in the video code), and you should report that back to the user. In our polling loop or webhook, include checks for errors and react accordingly (e.g., log them and return an error message). Putting It All Together User requests a video (perhaps by clicking a button on your site). The front-end calls POST /api/render-video with the desired composition and props. The Vercel serverless function ( render-video ) triggers the Remotion Lambda render and returns a renderId . The front-end then calls GET /api/render-status?renderId=... every few seconds, or waits for a webhook to hit. Once the video is done, the status response provides the video URL. The front-end can then display a download link or automatically play the video from that URL. Follow these steps, and then you can leverage the strength of Vercel for quick API routing and the power of AWS Lambda for heavy-duty video rendering. This “best of both worlds” approach is exactly what the Remotion team advocates for dynamic video apps on Vercel.