Getting Setup
Set up self-managed Lambda rendering for the RVE SDK
This guide connects the RVE SDK to a Lambda renderer in your own AWS account. For more detail about each AWS step, see the Remotion Lambda setup guide.
You do these tasks:
- Configure AWS permissions.
- Deploy the Lambda function, the S3 bucket, and your composition.
- Add two API routes to your app.
- Connect the editor to the routes.
1. Configure AWS
You do this part one time for each AWS account.
Install the Lambda package
npm i --save-exact @remotion/lambda@4.0.481Use the same exact version for all @remotion/* packages and remotion. Do not use a ^ range.
Create the role policy
npx remotion lambda policies role- In the AWS console, go to IAM > Policies > Create policy.
- Paste the JSON output into the JSON editor.
- Name the policy
remotion-lambda-policy.
The policy gives the Lambda function the permissions it needs. For example, it lets the function read and write files in S3.
Create the role
- Go to IAM > Roles > Create role.
- Select Lambda as the use case.
- Attach
remotion-lambda-policy. - Name the role
remotion-lambda-role.
Create a user and access keys
- Go to IAM > Users > Create user. Do not give the user console access.
- Open the user, then go to Security credentials > Access keys.
- Create an access key and save the two values.
- Add the values to your
.envfile:
REMOTION_AWS_ACCESS_KEY_ID=xxx
REMOTION_AWS_SECRET_ACCESS_KEY=xxxKeep the keys secret
Use these keys only on your server. Do not commit the .env file.
Add the user policy
npx remotion lambda policies user- Open the user, then select Add permissions > Create inline policy.
- Paste the JSON output and create the policy.
Validate the permissions
npx remotion lambda policies validate2. Write and deploy your composition
The Lambda function renders a composition that you write. It must read the size, duration, frame rate, and scale from inputProps, and it must draw items inside LayerBox.
Put the entry point at remotion/index.ts in the root of your project.
Deploy with the SDK helper
The SDK includes a deploy() helper. It does these steps:
- Deploys the Lambda function, with a CloudWatch log group.
- Creates the S3 bucket, or uses the bucket that exists.
- Bundles
remotion/index.tsfrom the current working directory and deploys it as a site.
import dotenv from 'dotenv';
import { deploy } from '@reactvideoeditor/react-video-editor/utils/remotion/aws-lambda/deploy';
dotenv.config();
await deploy({
region: 'us-east-1',
siteName: 'my-video-editor',
ram: 3009,
disk: 10240,
timeout: 240,
});node deploy.mjs| Option | Type | Default | Description |
|---|---|---|---|
region | AwsRegion | 'us-east-1' | The AWS region for the function, bucket, and site |
siteName | string | 'my-awesome-site' | The site name. A deploy with the same name replaces the site |
ram | number | 3009 | The function memory in MB |
disk | number | 10240 | The function disk size in MB |
timeout | number | 240 | The function timeout in seconds |
- The helper needs
@remotion/lambda. It is an optional peer dependency of the SDK. - If
REMOTION_AWS_ACCESS_KEY_IDandREMOTION_AWS_SECRET_ACCESS_KEYare both missing, the helper shows a message and stops without a deploy. - The helper prints the function name, the bucket name, and the site name.
To get the Serve URL of the site and the function name, run these commands:
npx remotion lambda sites ls
npx remotion lambda functions lsDeploy with the CLI
You can also deploy with the CLI:
npx remotion lambda functions deploy
npx remotion lambda sites create remotion/index.ts --site-name=my-video-editorThe second command prints the Serve URL.
Redeploy after changes
Deploy the site again when you change the composition or upgrade the @remotion/* packages. If you use the same site name, the Serve URL does not change.
Check the AWS limits
npx remotion lambda quotasA new AWS account can have a low concurrency limit. If you need more concurrent renders, ask AWS to increase the limit.
3. Add the API routes
The HttpRenderer sends a POST request to {endpoint}/render and then to {endpoint}/progress. For the endpoint /api/lambda, create these two App Router files:
app/api/lambda/render/route.tsapp/api/lambda/progress/route.ts
Add these values to your .env file:
REMOTION_AWS_REGION=us-east-1
REMOTION_FUNCTION_NAME=remotion-render-4-0-481-mem3009mb-disk10240mb-240sec
REMOTION_SERVE_URL=https://remotionlambda-xxxx.s3.us-east-1.amazonaws.com/sites/my-video-editor/index.htmlThese names are examples. Use the function name and the Serve URL from your deploy.
Render route
The request body is { id, inputProps }. The response must contain the renderId and the bucketName.
import { renderMediaOnLambda, type AwsRegion } from '@remotion/lambda/client';
import { collectFontInfos } from '@/lib/collect-font-infos';
export async function POST(request: Request) {
const { id, inputProps } = await request.json();
const { renderId, bucketName } = await renderMediaOnLambda({
region: process.env.REMOTION_AWS_REGION as AwsRegion,
functionName: process.env.REMOTION_FUNCTION_NAME!,
serveUrl: process.env.REMOTION_SERVE_URL!,
// The id is the editor projectId. It must equal your composition id.
composition: id,
inputProps: {
...inputProps,
fontInfos: collectFontInfos(inputProps.tracks),
},
codec: 'h264',
downloadBehavior: { type: 'download', fileName: 'video.mp4' },
});
return Response.json({ renderId, bucketName });
}collectFontInfos is the function from Fonts. Without it, server renders use the fallback font.
Progress route
The request body is { id, bucketName }. The id is the renderId from the render route. The response must use one of these shapes:
| { type: 'progress'; progress: number } // progress from 0 to 1
| { type: 'done'; url: string; size: number } // size in bytes
| { type: 'error'; message: string }import { getRenderProgress, type AwsRegion } from '@remotion/lambda/client';
export async function POST(request: Request) {
const { id, bucketName } = await request.json();
const progress = await getRenderProgress({
renderId: id,
bucketName,
region: process.env.REMOTION_AWS_REGION as AwsRegion,
functionName: process.env.REMOTION_FUNCTION_NAME!,
});
if (progress.fatalErrorEncountered) {
return Response.json({
type: 'error',
message: progress.errors[0]?.message ?? 'The render failed.',
});
}
if (progress.done && progress.outputFile) {
return Response.json({
type: 'done',
url: progress.outputFile,
size: progress.outputSizeInBytes ?? 0,
});
}
return Response.json({ type: 'progress', progress: progress.overallProgress });
}The HttpRenderer also accepts a response in the shape { type: 'success', data }. It reads data from that shape.
4. Connect the editor
Create an HttpRenderer with the base endpoint of your routes. Give it to the customRenderer prop.
'use client';
import { useMemo } from 'react';
import { ReactVideoEditor } from '@reactvideoeditor/react-video-editor/react-video-editor';
import { HttpRenderer } from '@reactvideoeditor/react-video-editor/utils/http-renderer';
import '@reactvideoeditor/react-video-editor/styles.css';
export default function Page() {
const lambdaRenderer = useMemo(
() =>
new HttpRenderer(
'/api/lambda',
{ type: 'lambda', entryPoint: '/api/lambda' },
{ name: 'Lambda' },
),
[],
);
return (
<ReactVideoEditor
// Must equal the composition id, unless your render route uses a fixed id.
projectId="my-project"
fps={30}
customRenderer={lambdaRenderer}
/>
);
}- The editor uses cloud mode because an
HttpRendereris enabled by default. - The props set the render mode. The editor has no control that changes the mode. It does not change to browser mode when a cloud render fails.
- If you set
enableWebRender={true}and pass{ enabled: false }as the third argument, the editor uses browser mode. - The
nameoption sets the renderer name in the export dialog. The default is'Cloud'.
Related pages
- Custom compositions
- Common Lambda problems
- RVE Cloud Rendering, the managed alternative