Handling Millions of Property Photos: Storage, CDN, and Image Pipelines
How to build a property photo pipeline at scale: direct-to-cloud uploads, WebP and AVIF delivery, CDN edge transforms, and duplicate photo fraud detection.
If your listing pages are getting slower, your image bill is climbing faster than your traffic, and photo quality is all over the map because agents and owners upload whatever they have, the fix is almost never a single vendor. It is a pipeline. A property photo pipeline at scale separates into three concerns that most teams collapse into one too early: how photos get uploaded, how they get processed, and how they get delivered. Get those three boundaries right and most of the pain disappears before you ever shop for a CDN.
We have built and run listing-photo infrastructure inside real two-sided property marketplaces, Lamudi and LISTD, across Southeast Asia. This is the reference architecture we reach for, and, more usefully, the order in which things actually break as you go from thousands of photos to millions.
Why property photos are not a generic image workload
A generic image CDN tutorial assumes a controlled set of images uploaded by your own team. A property marketplace is the opposite. Photos arrive in batches of ten to forty per listing, from thousands of agents and owners with different phones, lighting, and standards. The cover photo and photo ordering drive click-through, so they are product decisions, not storage details. And the same physical unit gets photographed and re-listed by multiple agents, which turns duplicate detection into a fraud problem, not a housekeeping one.
That changes the design priorities. You are not optimizing one hero image. You are ingesting messy, high-volume, per-listing photo sets where quality directly moves lead conversion and where recycled photos are a trust signal you cannot ignore. Photo infrastructure sits inside the broader two-sided marketplace architecture, and the decisions here ripple into search, maps, and trust.
The pipeline in three layers
Treat the pipeline as three loosely coupled layers with clean handoffs:
- Upload: get the original bytes from the user's device into cloud object storage as directly as possible.
- Process: normalize, generate or transform variants, run moderation and duplicate checks, extract metadata.
- Deliver: serve the right size and format from a CDN close to the user.
The most common early mistake is building these as one monolith where the API server receives the upload, resizes inline, writes to storage, and serves from origin. That works at thousands of photos and collapses at millions. Keeping the layers separate lets you scale, replace, or optimize each independently, which is also what makes a later migration survivable.
Build, buy, or defer?
Before you architect anything, ask whether you need a dedicated pipeline at all. At a few thousand photos with uploads that flow through your API server without tipping it over, a single CDN in front of origin object storage is enough, and building more is premature optimization. A dedicated pipeline earns its keep only when one of three signals appears: your image bill is climbing faster than your traffic, upload spikes are straining your API tier, or recycled and low-quality photos have become a trust problem. Build for the scale you are entering, not the one you imagine.
Once you do need it, the real question is buy versus build, and it is a bandwidth decision, not a capability one. Buying means a vendor like Cloudinary, ImageKit, Cloudflare Images, or imgix: edge transforms, format negotiation, and moderation-adjacent tooling you can wire up in days rather than weeks, at a higher but predictable per-image cost. Building means AWS primitives, typically CloudFront with Lambda@Edge over an S3 image storage architecture (or GCS or R2): full control, lower cost if you run it well, and an ongoing operational load your team owns.
| Concern | Build (CloudFront plus Lambda@Edge) | Buy (image CDN vendor) |
|---|---|---|
| Control | Full | Constrained to their transforms |
| Cost at scale | Lower if you run it well | Higher but predictable |
| Time to ship | Weeks | Days |
| Moderation tooling | Build it | Often bundled |
| Ongoing ownership | Your team | The vendor |
A pragmatic middle path is common: buy the delivery layer to move fast, but keep uploads and moderation on your own primitives, where the marketplace-specific logic lives. Neither pure path is wrong. The failure mode we see most is choosing DIY for the control, then under-staffing the operational reality of running it.
Get uploads off your API servers
The single highest-leverage change for a straining setup is direct-to-cloud upload. Instead of routing image bytes through your application server, issue a short-lived presigned URL and let the browser or mobile client upload straight to S3, GCS, or R2.
This removes image traffic from your API tier entirely, which is usually the thing falling over first. It also lets you attach lifecycle rules that auto-delete abandoned or temporary uploads after roughly a day, so half-finished listings do not accumulate as storage cost. Processing then runs asynchronously off a storage event: an upload lands, a function picks it up, and moderation, variant generation, and metadata extraction happen out of the user's request path.
Where that photo metadata lives, meaning the listing-to-image relationship, the cover-photo flag, and display order, belongs in your data model, not smuggled into filenames or inferred from upload order.
Transform on the fly, do not pre-generate everything
There are two ways to produce the many sizes and crops a listing grid needs. You can pre-generate every variant at upload time, or you can transform on the fly and cache the result at the edge after the first request. For most listings marketplaces, on-the-fly wins.
The reason is operational, not just cost. The day you add a breakpoint, change your grid, or support a new device size, pre-generation means a batch job reprocessing millions of images. On-the-fly image resizing means you change a URL parameter and the edge fills its cache lazily. You stop paying to store variants nobody requests.
| Decision | Pre-generate all variants | Transform on the fly |
|---|---|---|
| New breakpoint or crop | Batch reprocess everything | Change a URL param |
| Storage cost | Grows with variant count | Store originals only |
| First-request latency | Fast, already built | One-time transform, then cached |
| Best fit | Small, fixed variant set | Marketplace with evolving UI |
The real cost driver is variant proliferation. Many breakpoints multiplied by many crops multiplied by several formats can quietly generate dozens of derivatives per photo. Constrain your variant matrix deliberately; that discipline matters more than raw storage optimization.
Edge delivery and modern formats
In 2026, good delivery means transforming near the edge, pulling from regional storage, rather than transforming at one central location and shipping bytes across the world. A CDN that only transforms in one place is now dated architecture. Serve modern formats by default: AVIF has crossed roughly 95 percent global browser support, so an AVIF-first strategy with a WebP fallback and a JPEG floor is the sensible baseline for WebP and AVIF optimization.
This is not a vanity metric. LCP on a listing page is almost always the hero photo, and image delivery speed is a measurable conversion lever. Fractional-second LCP improvements have been tied to meaningful conversion lifts on media-heavy pages. On thumbnail-dense surfaces like map-based property search, the same delivery discipline decides whether the map feels instant or sluggish.
Duplicate and watermark fraud: the part generic CDNs skip
This is where property marketplaces diverge hardest from generic image content. Agents recycle photos across stale listings, scrape competitor photos, and re-list the same unit under different accounts. Exact-hash matching catches none of it, because trimming a few pixels, flipping the image, or stamping a watermark changes the binary hash entirely.
You need perceptual hashing plus periodic reverse-image checks against your own catalog to catch near-duplicates, and computer-vision watermark and logo detection to flag scraped or stolen photos. An automated image moderation API, whether a managed service like Amazon Rekognition or a specialist like Sightengine, can return a verdict in well under a second per image, which means you can gate at upload time rather than review after publish. Note that AI tools which strip embedded watermarks create fresh legal exposure, so treat provenance as a policy question, not only a detection one.
Photo fraud is squarely a trust-and-safety concern, and it should share signals with the rest of your trust and safety system rather than living as an isolated image filter.
What gets expensive from thousands to millions
Raw origin storage is rarely the problem; originals are cheap. The costs that scale badly are CDN egress, transform compute on cache misses, and variant sprawl. CDN egress cost optimization comes down to caching aggressively so egress and compute are paid once per variant, capping the variant matrix so you are not multiplying work per photo, and expiring temporary uploads so abandoned listings do not linger. Control them in that order.
In low-connectivity markets, delivery discipline is not optional. Serving oversized images to users on unstable mobile connections in Southeast Asia tanks both experience and conversion, so aggressive format negotiation and mobile-first variants are core work, not polish you add later.
Migrating without a rewrite
Most teams reading this already have an image pipeline that is straining, not a blank page. You do not need a rewrite. Because the three layers are separable, you can migrate incrementally: put uploads behind presigned URLs first, introduce on-the-fly transforms behind your existing image URLs second, then move delivery to an edge setup, dual-serving old and new paths until the new one is proven. Expect the upload change to land in days and the full migration to run over weeks, not months, precisely because you are sequencing rather than rebuilding.
That sequencing, cheapest and highest-impact change first, is the same judgment we apply when deciding whether a marketplace should rebuild or refactor at all. Fix uploads and variant sprawl before you shop for a CDN vendor, and most of the pain you are feeling resolves before the expensive part of the project even starts.
Frequently asked questions
Should we store every resized image variant or generate them on the fly?
For most listings marketplaces, on-the-fly transformation cached at the edge after the first request beats pre-generating every variant. It avoids reprocessing millions of images every time you add a breakpoint or change your grid, and cost is driven mainly by how many distinct variants get requested, not by storing originals. Pre-generation only makes sense when your variant set is small and fixed.
How do we catch agents re-uploading the same photos across duplicate or stale listings?
Exact-hash matching alone misses cropped, flipped, or lightly edited copies. Use perceptual or near-duplicate hashing combined with periodic reverse-image checks against your own catalog to catch the copy-paste rental fraud pattern. Add computer-vision watermark detection to flag scraped or stolen photos.
Do we need a dedicated image CDN vendor, or can we build this on AWS primitives?
Both are viable, and the decision is about operational bandwidth, not capability. CloudFront with Lambda@Edge gives full control and can be cheaper at scale, while a vendor like Cloudinary, ImageKit, Cloudflare Images, or imgix gets you edge transforms and moderation-adjacent tooling faster. Choose based on whether your team wants to own that infrastructure long-term.
When is building a dedicated photo pipeline premature?
If you are under roughly tens of thousands of photos, uploads flow through your API server without tipping it over, and a single CDN in front of origin keeps listing pages fast, you probably do not need a dedicated pipeline yet. The signals that it is time: your image bill is outpacing traffic growth, upload spikes are straining your API tier, or duplicate and low-quality photos have become a trust problem. Build for the scale you are entering, not the scale you imagine.
What actually drives the cost as we scale from thousands to millions of photos?
Not raw storage. Originals are cheap. The costs that scale badly are CDN egress, transform compute on cache misses, and variant sprawl, meaning many breakpoints multiplied by many crops multiplied by several formats. Control them by caching aggressively so egress and compute are paid once per variant, capping your variant matrix, and expiring abandoned uploads. Storage optimization is the least important lever.
What should we fix first when our current image setup is straining?
Get uploads off your API server with presigned direct-to-storage uploads, and stop pre-generating unbounded image variants. Those two changes resolve the most common scaling pain before any CDN vendor migration is needed. Only after that is it worth shopping for edge delivery.