Dreep vs building your media pipeline on S3 and Lambda
On AWS you assemble presigned uploads, an S3 bucket, Lambda functions with a Sharp layer, FFmpeg packaging for video, a queue, CloudFront and signed URL logic, then operate all of it. The metered AWS bill is often small; the cost is engineering time. Dreep replaces those parts with one API and SDK. Building wins at very large scale or with custom pipelines.
The DIY architecture
A typical do-it-yourself pipeline on AWS. Every box is code or configuration your team writes, deploys, monitors and upgrades.
Presign API
API Gateway + Lambda, auth, S3 presigned PUT
S3 originals
Bucket, CORS, lifecycle, event notifications
Queue + workers
SQS, Sharp Lambda, FFmpeg runtime, DLQs
S3 variants
Key scheme, dedupe, orphan cleanup
CloudFront
Origins, cache policy, signed URLs, invalidation
Component by component: what you own
The left column is what a production pipeline on AWS needs. The right column is what replaces it with Dreep.
| Component | Build it on AWS | With Dreep |
|---|---|---|
| Upload authorisation | Lambda that checks the user and signs an S3 PUT | Your backend checks the user, then calls presignUpload |
| Upload validation | Content-Type and size conditions in the presign, plus server-side checks | Type allow-list, 500 MB cap, Content-Type and Content-Length must match the presign |
| Unconfirmed uploads | Track state, sweep orphans with a scheduled job | Assets stay pending until confirmUpload and are excluded from listings |
| Image resizing | Sharp on Lambda: native build, layer, memory tuning | width, height, fit, gravity, dpr, rotate, blur, radius as URL params |
| Format conversion | Your own Accept header negotiation and cache keys | format=webp, avif, jpeg, png, gif or tiff, chosen explicitly |
| Variant cache | Key scheme in S3, cache policy in CloudFront | Generated on first request, then served from cache |
| Video transcoding | FFmpeg binary or container, or a managed transcoder, plus a job queue | format, videoCodec, fps, trimStart, trimEnd on the same URL; heavy jobs return 202 |
| HLS streaming | Segmenting, manifests, CORS for players | format=hls returns a .m3u8 manifest and segments |
| Signed URLs | CloudFront key groups, key rotation, policy signing | Signed folders; signedUrl() computes HMAC-SHA256 locally |
| OCR and background removal | Separate services, separate IAM and billing | format=txt for OCR; POST /bg-remove |
| Usage limits | Build metering and per-tenant quotas | Plan quotas with LIMIT_EXCEEDED, add-ons when you need more |
| SDKs | Write your own wrappers | Typed JavaScript and Go SDKs, plain REST for the rest |
Where the maintenance actually goes
Sharp and libvips builds
Sharp ships native binaries, so the layer must be built for Lambda's Linux and the exact architecture (x86_64 or arm64) of the function. Every Node.js runtime upgrade means rebuilding and retesting it, inside Lambda's 250 MB unzipped limit for code plus layers.
Cold starts
Image libraries and FFmpeg make deployment packages large, which lengthens initialisation. The fixes are provisioned concurrency, which you pay for while idle, or accepting slow first requests after quiet periods.
FFmpeg packaging and limits
You maintain a static FFmpeg build or a container image, and work within a 15-minute maximum invocation and the /tmp size you configure. Long videos push you to chunking, Fargate or a managed transcoder, which is a second system.
Cache invalidation
Changing a variant at a fixed URL means CloudFront invalidations. AWS includes 1,000 paths a month, then charges $0.005 per path at the time of writing. Most teams switch to versioned keys, which means migrating every stored URL.
Signed URL logic
CloudFront signed URLs need public keys, key groups, a private key in your secrets store, rotation, and code that builds canned or custom policies. Getting expiry and path scoping wrong exposes private media.
The long tail
HEIC input, EXIF orientation, animated GIFs, dead-letter queues, retries that don't double-write, per-tenant quotas and alarms. None is hard alone; together they are a standing maintenance cost.
A worked cost example
Assumptions: AWS US East pay-as-you-go prices at the time of writing (October 2026), free tiers applied; 40 GB stored; 20,000 image uploads and 40,000 newly generated variants a month; each variant is a 1,536 MB Lambda running 0.6 s; 3 million CDN requests and 400 GB of egress. Images only.
| Line item | Usage | Approx. monthly cost |
|---|---|---|
| Lambda compute | 36,000 GB-seconds at $0.0000166667 | $0 (inside the 400,000 GB-s free tier), $0.60 without it |
| Lambda requests | About 60,000 at $0.20 per million | $0 (inside the 1M free tier) |
| S3 Standard storage | 40 GB at about $0.023 per GB-month | About $0.92 |
| S3 PUT requests | 60,000 at $0.005 per 1,000 | About $0.30 |
| S3 GET requests | About 80,000 at $0.0004 per 1,000 | About $0.03 |
| CloudFront | 400 GB and 3M HTTPS requests | $0 (inside 1 TB and 10M request always-free tier) |
| Total AWS bill | About $1.25 a month |
At this volume the AWS bill is lower than Dreep Pro at $5.99 a month (50 GB storage, 50,000 image and 4,000 video transformations), so infrastructure price alone is not the reason to buy. The real comparison is engineering time: building, testing and operating the pipeline above, then upgrading it every time Node.js, Sharp or FFmpeg moves. Put your own day rate against that. Video, OCR and signed delivery widen the gap, because each is another system on AWS. Past 1 TB of egress or 10 million requests, CloudFront charges begin (for example $0.085 per GB in the US and Europe for the next 9 TB), so rerun the numbers for your traffic.
What replaces the stack
Upload, resize and sign: the three things the architecture above exists to do, with the real Dreep SDK calls.
import { Dreep } from "dreep";
const dreep = new Dreep({
apiKey: process.env.DREEP_API_KEY,
signingSecret: process.env.DREEP_SIGNING_SECRET,
});
const asset = await dreep.upload({ file, folder: "products" });
// Replaces the Sharp Lambda and the variant cache
dreep.url(asset, { width: 600, height: 600, fit: "cover", format: "avif" });
// Replaces CloudFront key groups and policy signing
dreep.signedUrl(asset, { expiresIn: 900 });client, err := dreep.New(
os.Getenv("DREEP_API_KEY"),
dreep.WithSigningSecret(os.Getenv("DREEP_SIGNING_SECRET")),
)
asset, err := client.Upload(ctx, dreep.UploadOptions{
File: f, Filename: "shoe.jpg",
Destination: dreep.Destination{Folder: "products"},
})
thumb := client.URL(asset.ID, &dreep.Transform{Width: 600, Height: 600, Fit: dreep.FitCover, Format: dreep.FormatAVIF})
signed, err := client.SignedURL(asset.ID, 15*time.Minute, nil)curl -X POST https://api.dreep.cloud/api/v1/upload \
-H "Authorization: Bearer $DREEP_API_KEY" \
-F "file=@shoe.jpg" -F "folder=products"
# Then request any size from the returned URL:
# https://cdn.dreep.cloud/api/v1/fetch/<id>.jpg?width=600&height=600&fit=cover&format=avifWhen building it yourself is the right call
Very large, steady volume
At hundreds of millions of variants a month with predictable traffic, committed-use discounts and a dedicated platform team can beat any per-plan pricing.
Custom processing
Watermarks and overlays, ML moderation, proprietary codecs or bespoke colour pipelines. Dreep doesn't offer watermarking or arbitrary code in the pipeline.
Strict in-VPC requirements
If media may never be touched by a third party, keep it in your VPC with S3 endpoints. Dreep's BYOB keeps storage in your account, but Dreep still processes the bytes.
Event-driven workflows
If downstream systems must react to 'variant ready' events, S3 notifications and EventBridge give you that. Dreep has no webhooks; you poll the URL until it returns 200.
Who this is for
- Small teams who would rather ship product than maintain Sharp layers and FFmpeg builds.
- Apps that need images, video, OCR and signed delivery behind one API.
- Teams who want storage in their own S3 bucket but not the pipeline: use BYOB on Starter or Pro.
When Dreep is not the right fit
- Platforms at very large, steady volume with a dedicated media infrastructure team.
- Pipelines that need watermarks, custom ML steps or webhooks on completion.
- Environments where no third party may process the media.
Frequently asked questions
Does building on S3 and Lambda cost less than Dreep?
Often, on the AWS bill alone. In the worked example above it comes to about $1.25 a month. The difference is the engineering time to build and maintain the pipeline, plus video, OCR and signed delivery, each of which is another system to run.
Can I keep my media in S3 and still use Dreep?
Yes. On Starter or Pro, connect your own S3 bucket to an empty project. Dreep stores originals and variants in it and handles processing and delivery.
How hard is it to run Sharp on AWS Lambda?
It works, but Sharp ships native libvips binaries, so you build the layer for Lambda's Linux and the function's architecture, keep it under the 250 MB unzipped limit, and rebuild it on runtime upgrades.
Can Lambda transcode video with FFmpeg?
For short clips, yes, using a static FFmpeg build or a container image. The 15-minute invocation limit and /tmp sizing push longer videos to chunking, Fargate or a managed transcoder.
Does Dreep support webhooks like S3 event notifications?
No. Light video jobs return 200 directly; heavy ones return 202 while processing, and you request the same URL again until it returns 200.
Can I migrate an existing S3 media library into Dreep?
Yes. The S3 import in the Dreep dashboard connects to your bucket, lets you choose objects and a destination folder, and copies them into a Dreep project as a background job with progress and logs. If you would rather new uploads stay in your own bucket, connect it with BYOB instead.
Related
Connect Amazon S3
Keep storage in your bucket with a four-action IAM policy.
Video transcoding API
The video side of the pipeline, without FFmpeg builds.
Secure file uploads
Presigned uploads and what Dreep validates.
Pricing
Free, Starter and Pro plans with add-ons.
Documentation
Uploads, transforms and signed URLs.
Skip the Sharp layer and the FFmpeg build
Start on the free plan, upload one file, and request any size or format of it by changing URL parameters.