Server-Side Image Thumbnail Generation: WebP, AVIF, Queues

Solving LCP and Page Weight: Automated Image Thumbnail Generation

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1033
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    554

Solving LCP and Page Weight: Automated Image Thumbnail Generation

Is your site loaded with images slow? Each page serves originals at 4000x3000 pixels – LCP skyrockets and users leave. Our experience shows that automatic server-side thumbnail generation is the only way to keep Core Web Vitals in check without manual processing of every file. We implement a turnkey solution in 2–3 days: queue setup, WebP/AVIF formats, CDN caching. This cuts data transfer volume by 40–60% and improves LCP by 30–50%, directly impacting conversion.

How Queue-Based Thumbnail Generation Works

Asynchronous generation is the standard for modern high-upload-load projects. After the user uploads an original to S3 or local storage, a task is dispatched to a queue (Laravel Job, BullMQ, or AWS SQS). It creates several sizes: thumb (200x200) for lists, medium (600x400) for cards, large (1200x800) for galleries. The user doesn't wait – the response comes immediately, and thumbnails appear seconds later. The queue does not block the web server; processing happens in the background.

Why Choose WebP/AVIF?

Modern lossy compression formats save 25–50% in size without noticeable quality loss. For browsers that do not support AVIF, WebP is automatically served via the <picture> element. This reduces LCP by 30–50%. AVIF (based on AV1) offers the best compression but requires more CPU resources for encoding. WebP is a universal choice, supported by 96% of browsers.

Choosing a Generation Strategy: Queue vs Lazy Generation

For sites with high upload frequency (photo galleries, marketplaces), an async queue is the only option – it doesn't block responses and allows horizontal scaling. Lazy generation via Glide suits projects with infrequent uploads or when thumbnail sizes are unknown in advance. It generates the image on the first request and caches it. However, the first visitor experiences generation latency. We help choose a strategy based on your metrics: daily upload count, average image size, infrastructure budget.

What's Included in Our Work

  • Audit of current image storage and processing system
  • Strategy selection: queue or lazy generation
  • Implementation of thumbnail generation with required sizes and formats
  • Caching setup (CDN, Cache-Control)
  • Integration with existing API and storage (S3, cloud server)
  • Documentation for use and maintenance

Why Sharp Outperforms Competitors

The Sharp library (based on libvips) performs operations 4–5 times faster than ImageMagick or GD for typical tasks. This is achieved by working with the image in RAM without intermediate files and efficient CPU cache usage. For Node.js projects, Sharp is the de facto standard. For PHP projects, we recommend Intervention Image with queues or Glide for lazy generation.

Formats and Optimization: Comparison

Format Size relative to JPEG Compatibility Recommended quality
JPEG 100% (baseline) All browsers 85%
WebP 70–80% 96%+ 80%
AVIF 40–60% 90%+ 60%
// Format selection based on browser support const output = sharp(buffer) .resize(800) .toFormat(supportsAvif ? 'avif' : supportsWebp ? 'webp' : 'jpeg', { quality: supportsAvif ? 60 : supportsWebp ? 80 : 85, }); 

AVIF gives up to 50% savings over JPEG at the same quality. WebP is supported by all modern browsers. For maximum compatibility, use <picture> with multiple formats.

Laravel: Intervention Image + Queue

// Model with automatic thumbnail generation class Image extends Model { const SIZES = [ 'thumb' => [200, 200], 'medium' => [600, 400], 'large' => [1200, 800], ]; } // Job for asynchronous generation class GenerateImageThumbnails implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable; public function __construct(private Image $image) {} public function handle(): void { $originalPath = Storage::disk('s3')->path($this->image->path); $img = \Intervention\Image\Facades\Image::make($originalPath); foreach (Image::SIZES as $size => [$width, $height]) { $resized = clone $img; $resized->fit($width, $height); // center crop $thumbPath = str_replace('original/', "{$size}/", $this->image->path); Storage::disk('s3')->put($thumbPath, $resized->encode('webp', 85)->__toString()); } $this->image->update(['processed' => true]); } } // Upload controller public function store(Request $request): JsonResponse { $path = Storage::disk('s3')->putFile('original', $request->file('image')); $image = Image::create([ 'path' => $path, 'user_id' => auth()->id(), 'processed' => false, ]); GenerateImageThumbnails::dispatch($image); return response()->json(['id' => $image->id]); } 

Node.js: Sharp

Sharp is the fastest Node.js library for image processing (based on libvips).

import sharp from 'sharp'; import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3'; const SIZES = { thumb: { width: 200, height: 200 }, medium: { width: 600, height: 400 }, large: { width: 1200, height: 800 }, } as const; async function generateThumbnails(s3Key: string): Promise<Record<string, string>> { const s3 = new S3Client({ region: 'eu-west-1' }); // Download original const { Body } = await s3.send(new GetObjectCommand({ Bucket: process.env.S3_BUCKET!, Key: s3Key, })); const buffer = Buffer.from(await (Body as any).transformToByteArray()); const results: Record<string, string> = {}; await Promise.all( Object.entries(SIZES).map(async ([name, { width, height }]) => { const thumbnail = await sharp(buffer) .resize(width, height, { fit: 'cover', position: 'centre' }) .webp({ quality: 85 }) .toBuffer(); const thumbKey = s3Key.replace('original/', `${name}/`).replace(/\.[^.]+$/, '.webp'); await s3.send(new PutObjectCommand({ Bucket: process.env.S3_BUCKET!, Key: thumbKey, Body: thumbnail, ContentType: 'image/webp', CacheControl: 'public, max-age=31536000', })); results[name] = thumbKey; }) ); return results; } 

Lazy Generation via Glide (PHP)

Glide generates thumbnails on request with a signed URL:

// Route for images Route::get('/img/{path}', function (Request $request, string $path) { $server = League\Glide\ServerFactory::create([ 'source' => Storage::disk('s3')->getDriver(), 'cache' => Storage::disk('local')->getDriver(), 'cache_path_prefix' => '.cache', 'base_url' => '/img', 'max_image_size' => 2000 * 2000, ]); // Validate URL signature League\Glide\Signatures\SignatureFactory::create(config('app.key')) ->validateRequest('/img/' . $path, $request->all()); return $server->getImageResponse($path, $request->all()); })->where('path', '.*'); // Generate signed URL $url = (new League\Glide\Urls\UrlBuilderFactory) ->create('/img', config('app.key')) ->getUrl('uploads/photo.jpg', ['w' => 400, 'h' => 300, 'fit' => 'crop']); 

Timeline and Cost

Queue-based thumbnail generation (Laravel Job or BullMQ Worker) with S3 storage: 2–3 days. Lazy generation via Glide with CDN caching: 3–4 days. Complex projects with multiple CMS integrations: up to 5 days. Cost is calculated individually based on complexity and stack. Contact us for a consultation and exact timeline. Order an audit and image optimization – we will select the optimal strategy for your project.

Our engineers have 5+ years of experience optimizing high-load sites. More than 30 projects with similar architecture are successfully running in production. Get a consultation – we will assess your project and propose a turnkey solution, guaranteeing a 30–50% LCP reduction after implementation.