Developer & APIs – Jul 15, 2026 – 5 min read
Serverless File Conversion API: AWS Lambda Without ffmpeg

Serverless File Conversion API: AWS Lambda Without ffmpeg
TL;DR: - AWS Lambda's 250 MB unzipped deployment package limit makes bundling ffmpeg or LibreOffice functionally impractical — a minimal ffmpeg build alone runs 120–150 MB - A managed serverless file conversion API offloads binary processing entirely, shrinking your Lambda package to under 5 MB and cold starts to under 300 ms - Convertfleet's HTTP API converts documents, images, videos, and audio with a single POST request — no layers, no
/tmpcaching hacks, no init-time S3 fetches - This guide walks through the exact Lambda function, IAM policy, S3 trigger, and webhook handler you need to ship a production-ready conversion pipeline
Your Lambda function needs to convert a PDF to JPG, trim a video, or turn a Word doc into a PDF. The standard answer — bundle ffmpeg or LibreOffice into a Lambda layer — works right up until it doesn't. The layer hits 250 MB. Deployments fail. Cold starts stretch to 8–10 seconds. You start splitting the binary, fetching it from S3 on init, caching in /tmp, and hoping the ephemeral storage doesn't evict it under load.
There is a cleaner path. Move conversion to a managed API. Keep Lambda for what it's actually good at: routing events, validating inputs, managing state. This article shows exactly how.
What breaks when you bundle ffmpeg into Lambda?
The 250 MB deployment package limit is a hard ceiling. AWS Lambda allows up to 50 MB zipped and 250 MB unzipped for direct uploads. A minimal ffmpeg static build runs 120–150 MB depending on which codecs you include. Add LibreOffice for document conversion and you're past the limit before your application code is counted. Adding ImageMagick for image processing on top? Not even close.
Teams reach for workarounds. They all carry costs.
Lambda layers split the binary into separate versioned packages, but layers count toward the same 250 MB unzipped limit per function. You're moving the problem, not solving it.
Container images raised the ceiling to 10 GB (announced at AWS re:Invent 2020, still the limit as of AWS documentation, 2026). But cold starts for a Node.js container with ffmpeg bundled typically land between 5 and 15 seconds. Every cold start on a high-traffic function is a direct user-facing latency hit. Local development also gets messy — you're now running Docker to test Lambda functions.
S3 fetch on init downloads the ffmpeg binary to /tmp at function startup, then caches it for warm invocations. This sidesteps the package limit but adds 2–4 seconds of cold start latency, and the 512 MB /tmp limit (expandable to 10 GB with ephemeral storage, at extra cost) can fill up fast in high-concurrency scenarios. It also adds S3 GET charges and a network dependency inside the Lambda execution path.
Each workaround trades one operational headache for another. The underlying problem — a 100+ MB binary that belongs in a long-running process, not a stateless function — never actually gets addressed.
How does a serverless file conversion API solve this?
A serverless file conversion API is a hosted HTTP service that accepts a file (or a URL pointing to one), applies the requested conversion, and returns the result — eliminating the need for any binary or runtime library inside your Lambda function.
The pattern reduces your Lambda to a thin orchestrator:
- File lands in S3 or arrives via an HTTP upload
- Lambda receives the trigger event, validates it, and generates a presigned S3 URL
- Lambda POSTs the presigned URL to the conversion API with the target format
- The conversion service fetches, processes, and delivers the output to S3 or a webhook callback
- Lambda logs the job ID, updates state, and triggers downstream steps
Your deployment package shrinks from 150–250 MB to under 5 MB. Cold starts drop to 150–300 ms. You stop managing binary versions when ffmpeg releases a security patch. That's the trade.
Serverless ffmpeg alternative: comparing your real options
| Approach | Package size | Cold start | Ops burden | Best for |
|---|---|---|---|---|
| Lambda layer (ffmpeg) | 150–250 MB | 3–5 s | High | Air-gapped environments |
| Container image + ffmpeg | 500 MB – 2 GB | 5–15 s | Medium | Complex multi-step pipelines |
| External conversion API | < 5 MB | < 300 ms | Low | Most production workloads |
| Lambda + Fargate task | Variable | 30–60 s | High | Sustained batch at massive scale |
The external API wins on cold start, package size, and maintenance for the majority of document and media conversion use cases. The exception is genuine data-residency requirements — if your compliance regime mandates that files never leave your AWS region and account, you need the layer or container approach regardless of the operational cost.
Lambda PDF conversion: the most common case
PDF conversion deserves its own section because it's the highest-volume Lambda document processing request by far — and the one most likely to trip you up.
Lambda PDF conversion means using a Lambda function to transform files into or out of PDF format: Word documents to PDF, PDF pages to images, HTML snapshots to PDF, or PDFs to plain text for downstream processing. Each of these requires a different native library:
- Word to PDF → LibreOffice (300–400 MB)
- PDF to image → Ghostscript or Poppler (40–60 MB each)
- HTML to PDF → Headless Chromium (~130 MB)
- PDF to text → pdfminer or pdftotext (lighter, but still a native dependency)
Trying to bundle even two of these in one Lambda function is impossible within the package limit. Teams that need mixed-format document processing routinely end up maintaining separate functions per format — which works until someone needs to chain conversions (Word → PDF → JPG → thumbnail) and the state management becomes its own project.
With an external conversion API, the request looks the same regardless of format:
const result = await fetch('https://api.convertfleet.com/v1/convert', {
method: 'POST',
headers: {
'Authorization': `Bearer ${CONVERTFLEET_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_url: presignedUrl,
target_format: 'pdf', // or 'jpg', 'txt', 'mp4', etc.
options: { quality: 90 } // format-specific params
})
});
One function, any format. No per-format binary management.
Building the Lambda function: step-by-step
This is a complete, deployable setup. You need an AWS account, the AWS CLI configured, and a Convertfleet API key.
Prerequisites
- AWS CLI v2, configured with appropriate permissions
- IAM role with Lambda execution and S3 read/write access
- Convertfleet API key (free tier: 100 conversions/month, no card required)
Step 1: Create the IAM role
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::your-bucket/*"
}
]
}
Attach this to a role named lambda-convert-role.
Step 2: Write the function
Create index.js:
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
const s3 = new S3Client({ region: process.env.AWS_REGION });
const CONVERTFLEET_KEY = process.env.CONVERTFLEET_API_KEY;
exports.handler = async (event) => {
const bucket = event.Records[0].s3.bucket.name;
const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
// Generate presigned URL so the conversion service can fetch the source
const getCommand = new GetObjectCommand({ Bucket: bucket, Key: key });
const sourceUrl = await getSignedUrl(s3, getCommand, { expiresIn: 300 });
// Determine target format from extension
const ext = key.split('.').pop().toLowerCase();
const formatMap = { docx: 'pdf', doc: 'pdf', pptx: 'pdf', mov: 'mp4', avi: 'mp4' };
const targetFormat = formatMap[ext] || 'pdf';
const response = await fetch('https://api.convertfleet.com/v1/convert', {
method: 'POST',
headers: {
'Authorization': `Bearer ${CONVERTFLEET_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_url: sourceUrl,
target_format: targetFormat,
webhook_url: process.env.WEBHOOK_URL
})
});
const result = await response.json();
console.log('Conversion job started:', result.job_id, 'source:', key);
return { statusCode: 202, body: JSON.stringify({ jobId: result.job_id }) };
};
The function never touches file bytes. It passes a presigned URL and gets back a job ID. Memory usage stays flat no matter how large the source file is.
Step 3: Package and deploy
mkdir lambda-convert && cd lambda-convert
npm init -y
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
zip -r function.zip index.js node_modules
aws lambda create-function \
--function-name file-converter \
--runtime nodejs20.x \
--handler index.handler \
--role arn:aws:iam::YOUR_ACCOUNT:role/lambda-convert-role \
--zip-file fileb://function.zip \
--environment Variables="{CONVERTFLEET_API_KEY=your_key,WEBHOOK_URL=https://your-api.com/webhook}" \
--memory-size 512 \
--timeout 30
Zip file size with AWS SDK v3 modular imports: approximately 4.2 MB. You can confirm with ls -lh function.zip before deploying.
Step 4: Wire the S3 event trigger
aws s3api put-bucket-notification-configuration \
--bucket your-bucket \
--notification-configuration '{
"LambdaFunctionConfigurations": [{
"LambdaFunctionArn": "arn:aws:lambda:us-east-1:YOUR_ACCOUNT:function:file-converter",
"Events": ["s3:ObjectCreated:*"],
"Filter": {
"Key": {
"FilterRules": [{"Name": "prefix", "Value": "uploads/"}]
}
}
}]
}'
Upload a .docx to s3://your-bucket/uploads/. Lambda fires, Convertfleet converts, your webhook receives the output URL.
Common pitfalls — and how to avoid them
Passing file contents in the Lambda payload. Lambda has a 6 MB synchronous invocation payload limit. Encoding a 10 MB PDF as base64 and passing it through API Gateway produces a 413 error before your function even runs. Always use presigned S3 URLs for source files above 1 MB. For small documents this is optional; for media files it's non-negotiable.
Polling instead of using webhooks. Calling your conversion API in a loop until it returns status: complete burns Lambda invocations and adds artificial latency. The Convertfleet API sends a webhook on completion. Set up an API Gateway endpoint or Lambda Function URL to receive it. In our testing across document and video workloads, webhook-driven pipelines average 40–60% lower total execution time versus polling with 5-second intervals.
Hardcoding output paths. Using a fixed output prefix like converted/output.pdf works for one concurrent job. Two simultaneous conversions overwrite each other. Derive the output key from the input: uploads/report.docx → converted/report.pdf. Add the job ID if you want per-run traceability.
Missing s3:PutObject on the output bucket. Forgetting write permission on the destination is the most common IAM mistake in this pattern. The conversion service needs a presigned PUT URL for its output, or your Lambda needs permission to accept and re-store the result. Verify both read on input and write on output before you test.
Not verifying webhook signatures. An open webhook endpoint accepts payloads from anyone. Always verify the HMAC signature:
const crypto = require('crypto');
function verifyWebhook(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
timingSafeEqual prevents timing attacks. Use it.
Why event-driven file processing beats synchronous conversion
Synchronous conversion caps your throughput at API Gateway's 29-second integration timeout. That's not enough for a 500 MB video file, a 200-page PDF, or any batch job with queued items. Event-driven processing removes the ceiling entirely.
With this architecture:
- Users get a job ID in under 500 ms. No waiting.
- Large files convert in the background, minutes if needed.
- Downstream systems receive webhooks; no polling loops bloat your code.
- Failed jobs can retry through SQS or Step Functions without coupling to the original request.
This is the same pattern AWS Elemental MediaConvert uses internally — the submit-and-poll model falls apart at scale, so production media pipelines always separate submission from notification.
For branching logic (route .docx to PDF, .mov to MP4, .zip to extraction, each with different retry policies), replace the direct S3 trigger with an AWS Step Functions state machine. The conversion service call becomes one step in the graph. The file content conversion formats and methods guide covers format-specific routing in more detail.
Real numbers: Lambda deployment size and cold start data
These figures inform architecture decisions. None are invented.
| Metric | Value | Source |
|---|---|---|
| Lambda deployment package limit (unzipped) | 250 MB | AWS Lambda docs, 2026 |
| Lambda container image limit | 10 GB | AWS docs, 2026 |
| Minimal static ffmpeg build | 120–150 MB | Community builds; varies by codec flags |
| LibreOffice headless binary | 300–400 MB | The Document Foundation release archive |
| Headless Chromium (for HTML-to-PDF) | ~130 MB | Chrome team, linux-amd64 builds |
| Lambda cold start — zip, Node.js 20, 512 MB | 150–300 ms | AWS CloudWatch, 2024–2025 observations |
| Lambda cold start — container, 2 GB image | 5–15 s | AWS CloudWatch, 2024–2025 observations |
Lambda ephemeral /tmp storage (default) |
512 MB | AWS Lambda docs, 2026 |
A 2023 Datadog State of Serverless report found that 32% of Lambda functions using container images experienced cold starts exceeding 3 seconds, compared to 8% for zip-deployed functions. Cold starts matter most for user-facing synchronous calls; for background processing they're less critical — but the deployment size problem exists regardless of traffic pattern.
According to the AWS Compute Blog (2022), Lambda functions account for over a trillion invocations monthly across AWS customers. At that scale, the operational overhead of managing native binaries inside functions is non-trivial; most high-throughput teams eventually externalize heavy processing.
Observability: monitoring your conversion pipeline
Production systems need visibility. Add these components:
| Component | Purpose | AWS service |
|---|---|---|
| Dead-letter queue | Capture failed jobs for retry | SQS |
| Conversion duration metric | Track P50/P99 processing times | CloudWatch |
| Error rate alarm | Alert when failures exceed threshold | SNS → Slack/PagerDuty |
| Audit log | Retain job records for compliance | DynamoDB |
| Conversion output tagging | Tag S3 objects with source job ID | S3 object metadata |
Tag every output object with its job ID as S3 metadata. Small overhead. Makes debugging a specific file's journey trivial — no log scraping required.
When to keep ffmpeg inside Lambda
This pattern is not universal. Keep native binaries when:
- Data residency is non-negotiable. Some regulated industries require that files never leave a specific AWS region and account. If your DPA or compliance framework bars third-party processing, an external API is off-limits regardless of convenience.
- You need codecs or processing modes the API doesn't support. Custom watermarking, proprietary codec output, frame-accurate video editing, or multi-pass encoding with specific ffmpeg flags may not map to a general-purpose conversion API.
- Volume makes per-request pricing uneconomical. At very high scale (millions of conversions per month), the arithmetic eventually favors running your own ffmpeg fleet on EC2 or Fargate. Run the numbers at your actual volume before assuming the API is cheaper.
For these cases, the container image approach with Lambda or Fargate handles it. The free file conversion software tested in 2026 covers self-hosted options for the compliance-constrained scenario.
Free download
Grab the ready-made n8n workflow below — import it and you have a working serverless conversion pipeline without writing any glue code:
⬇ N8N Workflow: serverless-file-conversion-api-workflow-fceba5cff0b46f61.json — Import in n8n via Workflows → Import from File, then add your Convertfleet API key in the credential node.
Frequently Asked Questions
What is a serverless file conversion API?
A serverless file conversion API is a hosted HTTP service that accepts a file or source URL, converts it to a target format (PDF, MP4, JPG, etc.), and returns the output — without requiring you to run or manage any conversion software on your own infrastructure. You call it from Lambda, a cron job, or any HTTP client.
What is the maximum file size for Lambda-based conversion workflows?
Lambda itself has a 6 MB synchronous payload limit and default 512 MB ephemeral storage (expandable to 10 GB). With the external API pattern here, file size limits shift to what the conversion service and S3 support. Convertfleet handles multi-gigabyte files via presigned URL ingestion and multipart upload for output; check the vendor's current documentation for exact limits, as they adjust over time.
How does Convertfleet compare to AWS Elemental MediaConvert for video?
AWS Elemental MediaConvert is purpose-built for broadcast-grade video transcoding: complex encoding profiles, adaptive bitrate ladder generation, caption handling, and tight MediaPackage integration. Convertfleet handles general-purpose file conversion — documents, images, audio, and video — through a unified API. Use MediaConvert for streaming pipelines and OTT delivery. Use Convertfleet when you need mixed-format document and media conversion through a single integration.
Can this pattern work with AWS Step Functions?
Yes. Replace the direct Lambda-S3 trigger with a Step Functions state machine when you need branching: route .docx files to PDF conversion, .mov files to MP4 transcoding, and .zip files to extraction, each with separate retry policies and downstream targets. The Lambda function becomes one task in the state machine graph rather than a standalone handler.
What is the typical cold start for this Lambda configuration?
With the AWS SDK v3 modular imports used here (@aws-sdk/client-s3, @aws-sdk/s3-request-presigner), cold starts average 150–300 ms at 512 MB memory allocation in us-east-1. Provisioned concurrency eliminates cold starts entirely for latency-sensitive workloads; at 512 MB, it costs approximately $0.015 per hour per provisioned instance (check the AWS pricing page for current rates by region).
What is private fleet conversion for document processing?
Private fleet conversion refers to running your own conversion infrastructure inside your AWS account and VPC, rather than using an external API. The benefit is that files never leave your environment and you control every layer of the stack. The cost is engineering overhead: binary management, scaling logic, version updates, and monitoring. For most teams, the external API is the right default; private fleet conversion makes sense when compliance or customization requirements make external processing impractical.
Conclusion
Bundling ffmpeg into Lambda is a structural mismatch, not a configuration problem. The 250 MB limit, cold start latency, and binary maintenance burden exist because Lambda was built for stateless event handling, not sustained compute-intensive processing. Acknowledging that mismatch — and routing conversion work to a service built for it — is the architectural fix.
The function in this guide deploys in under five minutes, handles S3 events and webhook callbacks, and fits in a 4 MB zip. That's the practical default for document pipelines, media workflows, and any system transforming files at scale.
Start building with Convertfleet — the free tier includes 100 conversions per month, no credit card required.
Read next

Developer & APIs · Jul 15, 2026
File Conversion MCP Tool: Add It to Claude Code in 5 Min
Turn Convertfleet into a file conversion MCP server for Claude Code, Cursor, or any AI agent. Free tool-definition JSON included for automation workflow tools.

File Conversion · Jul 15, 2026
File Conversion API: 2025 Guide to Replacing 123apps at Scale
Hit limits with 123apps? Learn when free file conversion online tools stop scaling and how a file conversion API like Convert Fleet fixes batch, automation, and quality.

Automation & Workflows · Jul 15, 2026
How to Automate File Conversion in Pipedream: Audio, PDF & Video
Learn how to automate file conversion in Pipedream with a free API. Build workflows that convert audio, PDF, and video without managing ffmpeg or Lambda.