Video Editing Rate Calculator from Overhead and Render Cost
By RenderComp Team Editorial policy
Remotion executes your React component once per frame. The output is identical on every run given the same props. That determinism is valuable to clients, and it also means a render has a legible cost structure — not a creative session priced by intuition.
Traditional editing rates bundle software seats, storage, machine depreciation, and the editor’s time into a single hourly figure. Remotion separates those concerns. The license fee, the Lambda execution that processes each frame, and the human time to configure the composition bill independently. Understanding each component’s magnitude is what makes an agency rate defensible when a client asks how you arrived at the number.
License Cost Per Render
Remotion offers two commercial license tiers. The Creators license costs $25 per seat per month with no minimum seat count or spend commitment. The Automators license bills at $0.01 per render with a $100 per month floor, so each render carries a minimum effective cost of $100 divided by that month’s total until the variable total exceeds $100 at 10,000 renders.
Encode both tiers as constants and expose the model as a parameter so the comparison stays live as your volume changes:
// rate-model.ts
const CREATORS_SEAT_PRICE = 25; // USD/seat/month
const AUTOMATORS_PER_RENDER = 0.01; // USD/render
const AUTOMATORS_MONTHLY_MIN = 100; // USD/month minimum spend
function licensePerRender(
model: 'creators' | 'automators',
seats: number,
rendersPerMonth: number,
): number {
if (model === 'creators') {
return (seats * CREATORS_SEAT_PRICE) / rendersPerMonth;
}
// Automators minimum kicks in below 10,000 renders/month at $0.01 each
const variable = rendersPerMonth * AUTOMATORS_PER_RENDER;
return Math.max(variable, AUTOMATORS_MONTHLY_MIN) / rendersPerMonth;
}
At 10,000 renders per month with one Creators seat, the license costs $0.0025 per render — one quarter of the Automators floor rate at the same volume. Below 10,000 renders the Automators minimum is $100 regardless of count, while Creators stays flat at $25 per seat. Building the crossover into the model means changing one string to switch tiers rather than rethinking the accounting.
Some usage patterns require a company license rather than an individual Creators or Automators license. The Remotion repository documents those cases; verify your deployment against those terms before billing at production scale.
Lambda Compute Cost
Each Remotion Lambda render runs as a single AWS Lambda invocation. A function can execute for up to 15 minutes and use as much as 10,240 MB of memory. Memory controls CPU allocation directly: at 1,769 MB the function receives the equivalent of one vCPU, so 3,538 MB yields two vCPUs. Doubling memory roughly halves render time while keeping per-frame compute cost flat — more memory per second, fewer seconds total.
The available storage per Lambda function is capped at 10 GB, covering intermediate frame files for the duration of one render job. Each execution environment instance handles up to 10 synchronous requests per second. The default concurrency limit across a region is 1,000 simultaneous Lambda executions; AWS can raise that ceiling on request, but 1,000 is what any account starts with.
AWS Lambda pricing varies by region and changes over time, so the function below accepts rates as parameters rather than encoding them:
// rate-model.ts (continued)
export type LambdaConfig = {
memoryMb: number; // 1769 = 1 vCPU, 3538 = 2 vCPU, max 10240
durationSec: number; // measured render time, not composition duration
gbSecondRate: number; // from AWS Lambda pricing for your region
perRequestRate: number; // from AWS Lambda pricing for your region
};
function lambdaCostPerRender(cfg: LambdaConfig): number {
const memGb = cfg.memoryMb / 1024;
return memGb * cfg.durationSec * cfg.gbSecondRate + cfg.perRequestRate;
}
Remotion notes that typical users render multiple minutes of video for a few cents. That tracks with Lambda’s pricing structure at reasonable memory and duration settings — the compute cost per render is almost never the line item that determines your agency rate.
Labor and Overhead
Compute and license costs are small in practice. The dominant cost for most agency work is human time: writing the composition template, adapting it per client, and reviewing the rendered output. This function models per-render labor separately from the compute line:
// rate-model.ts (continued)
function laborPerRender(
minutesPerRender: number, // per-job configuration and QA
hourlyLaborRate: number, // fully-loaded hourly cost for this role
overheadMultiplier: number, // covers software, benefits, facilities
): number {
return (minutesPerRender / 60) * hourlyLaborRate * overheadMultiplier;
}
The overhead multiplier captures costs that do not appear on any single invoice line. A multiplier of 1.35 means for every dollar of raw labor, you spend 35 cents on everything else. That figure is specific to your P&L; the function accepts it as a parameter rather than baking in an assumption.
Assembling the Rate
All three components are explicit, so the final rate is a sum plus a margin multiplier:
// rate-model.ts (continued)
type RateInputs = {
licenseModel: 'creators' | 'automators';
seats: number;
rendersPerMonth: number;
lambda: LambdaConfig;
minutesPerRender: number;
hourlyLaborRate: number;
overheadMultiplier: number;
marginMultiplier: number; // profit margin, kept separate from overhead
};
export type RateResult = {
licenseCostPerRender: number;
computeCostPerRender: number;
laborCostPerRender: number;
totalCost: number;
billingRate: number;
};
export function calculateRate(inputs: RateInputs): RateResult {
const licenseCostPerRender = licensePerRender(
inputs.licenseModel,
inputs.seats,
inputs.rendersPerMonth,
);
const computeCostPerRender = lambdaCostPerRender(inputs.lambda);
const laborCostPerRender = laborPerRender(
inputs.minutesPerRender,
inputs.hourlyLaborRate,
inputs.overheadMultiplier,
);
const totalCost =
licenseCostPerRender + computeCostPerRender + laborCostPerRender;
return {
licenseCostPerRender,
computeCostPerRender,
laborCostPerRender,
totalCost,
billingRate: totalCost * inputs.marginMultiplier,
};
}
The marginMultiplier is the only value not derived from a measured cost. Keeping it separate from overheadMultiplier means you can stress-test pricing scenarios without touching the cost accounting.
Rendering the Breakdown as a Composition
The calculateRate result is a plain object — exactly the shape of Remotion defaultProps. The composition below animates each cost bar with spring so the visual pacing matches the precision of the numbers behind it.
// RateBreakdown.tsx
import React from 'react';
import {
AbsoluteFill,
useCurrentFrame,
useVideoConfig,
spring,
interpolate,
Sequence,
} from 'remotion';
import type { RateResult } from './rate-model';
const CostBar: React.FC<{
label: string;
value: number;
total: number;
startFrame: number;
color: string;
}> = ({ label, value, total, startFrame, color }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// stiffness 80, damping 18: decisive settle within durationInFrames
const progress = spring({
frame: frame - startFrame,
fps,
config: { stiffness: 80, damping: 18 },
durationInFrames: 30,
});
const widthPct = interpolate(progress, [0, 1], [0, (value / total) * 75]);
return (
<div style={{ marginBottom: 20 }}>
<div style={{ fontSize: 13, marginBottom: 6, opacity: 0.7 }}>{label}</div>
<div
style={{
width: `${widthPct}%`,
height: 28,
backgroundColor: color,
borderRadius: 4,
}}
/>
<div style={{ fontSize: 12, marginTop: 4 }}>${value.toFixed(4)}</div>
</div>
);
};
export const RateBreakdown: React.FC<RateResult> = ({
licenseCostPerRender,
computeCostPerRender,
laborCostPerRender,
totalCost,
billingRate,
}) => (
<AbsoluteFill
style={{
backgroundColor: '#0d0d10',
padding: 56,
color: '#f0f0f0',
fontFamily: 'system-ui, sans-serif',
}}
>
<div style={{ fontSize: 22, fontWeight: 600, marginBottom: 36 }}>
Per-Render Cost Breakdown
</div>
<CostBar
label="License"
value={licenseCostPerRender}
total={totalCost}
startFrame={0}
color="#4f8ef7"
/>
<CostBar
label="Lambda Compute"
value={computeCostPerRender}
total={totalCost}
startFrame={10}
color="#f7a64f"
/>
<CostBar
label="Labor + Overhead"
value={laborCostPerRender}
total={totalCost}
startFrame={20}
color="#4ff7a6"
/>
<Sequence from={60}>
<div
style={{
marginTop: 40,
borderTop: '1px solid rgba(255,255,255,0.15)',
paddingTop: 28,
fontSize: 24,
fontWeight: 700,
}}
>
Billing Rate: ${billingRate.toFixed(2)}
</div>
</Sequence>
</AbsoluteFill>
);
Wire it into Root.tsx by passing the calculateRate result as defaultProps. The composition runs for 120 frames at 30 fps — 4 seconds. The three bars start at frames 0, 10, and 20 respectively, each completing their spring by roughly frame 50. The billing rate appears via Sequence at frame 60, leaving 60 frames of hold time for a still export or a freeze frame in a longer cut.
// Root.tsx (excerpt)
import { Composition } from 'remotion';
import { RateBreakdown } from './RateBreakdown';
import { calculateRate } from './rate-model';
const defaults = calculateRate({
licenseModel: 'automators',
seats: 1,
rendersPerMonth: 500,
lambda: {
memoryMb: 1769, // 1 vCPU equivalent
durationSec: 40, // replace with a measured render of your composition
gbSecondRate: 0, // replace with value from your region's Lambda pricing
perRequestRate: 0, // replace with value from your region's Lambda pricing
},
minutesPerRender: 12,
hourlyLaborRate: 75,
overheadMultiplier: 1.35,
marginMultiplier: 1.5,
});
export const RemotionRoot: React.FC = () => (
<Composition
id="RateBreakdown"
component={RateBreakdown}
durationInFrames={120}
fps={30}
width={1280}
height={720}
defaultProps={defaults}
/>
);
The durationSec field is the only input you cannot read off a pricing page. It comes from a test render of your actual composition. Run npx remotion render RateBreakdown once, check the wall-clock time the Lambda invocation reports, and use that number. Shorter compositions settle well under the 15-minute Lambda ceiling; compositions that pull in many external assets and long frame sequences will creep toward it.
Now available
Get 1,000+ Remotion Templates
Pay once — no subscription. Lifetime updates. TypeScript-first.
View pricing →