Dev
I Built AssetOps Images: A Full Laravel + React App That Optimizes 2,000 Images in Batches
Dev.toUnited States · NORTH AMERICA
WebP and AVIF conversion, image resizing, metadata removal, SEO-friendly filenames, background jobs, usage tracking, and an admin dashboard. Here’s how I put the pieces together. Imagine receiving a f...
WebP and AVIF conversion, image resizing, metadata removal, SEO-friendly filenames, background jobs, usage tracking, and an admin dashboard. Here’s how I put the pieces together.
Imagine receiving a folder containing 1,500 product images.
They need different dimensions, smaller file sizes, SEO-friendly filenames, and no sensitive GPS metadata. Once everything is processed, the files need to be organized, packaged, and delivered to the client.
You could handle everything manually. You could write a collection of scripts. Or you could build a proper application that handles the entire workflow.
I chose the third option.
Meet AssetOps Images — a complete, self-hosted image optimization web application built with Laravel 13, React 18, and TypeScript.
It started with a straightforward problem: image processing is easy until you need to do it consistently, at scale, and without losing track of what happened to every file.
The interesting part wasn’t converting JPEGs to WebP. It was building everything around that process.
Want to explore the finished product?
Get AssetOps Images on Gumroad
The real problem isn’t resizing images
Resizing an image takes a few lines of code. Building a reliable batch-processing workflow is a different challenge.
A useful image optimization platform needs to:
Accept large batches of images in different formats.
Analyze dimensions, orientation, EXIF data, GPS information, and color profiles.
Apply reusable processing configurations.
Resize images without unnecessarily upscaling them.
Convert images to WebP, AVIF, JPG, or PNG.
Remove sensitive metadata.
Generate consistent, SEO-friendly filenames.
Package the results into downloadable ZIP archives.
Track usage and enforce configurable quotas.
Handle failures without forcing users to restart an entire batch.
And there’s one more requirement: the application must remain responsive while all this work happens.
That last point influenced almost every architectural decision.
The stack behind AssetOps Images
I wanted a clear separation between the frontend, backend, and image-processing infrastructure.
LayerTechnologyBackendLaravel 13, PHP 8.3+FrontendReact 18, TypeScriptStylingTailwind CSSRouting and stateReact Router, ZustandDatabasePostgreSQL 16Background jobsRedis and Laravel queuesAuthenticationLaravel SanctumImage processingIntervention ImageDevelopment environmentDocker / DDEVBuild toolingVite
The frontend is a single-page application, while Laravel handles the API, authentication, business logic, and static frontend delivery.
The API exposes more than 60 documented endpoints, with API Resources providing consistent response structures.
The result is a straightforward deployment model: one application, clearly separated responsibilities, and infrastructure that can be configured without rewriting the core logic.
- Background jobs: the foundation of the entire workflow This was one of the most important decisions.
Imagine processing 2,000 images inside a single HTTP request. Even if it works locally, you’re creating an unnecessary risk of timeouts, memory pressure, and failed operations.
Instead, AssetOps splits the workflow into three stages.
Stage 1 — Analyze the files
The AnalyzeBatchFiles job inspects the uploaded images, extracts relevant metadata, detects GPS information, and generates thumbnails for the interface.
Stage 2 — Transform the images
The TransformBatchFiles job applies the selected settings: resizing, format conversion, quality adjustments, and metadata removal.
Stage 3 — Package the results
The PackageBatch job creates a ZIP archive containing the processed images, a metadata.csv manifest, and a processing-report.json file.
Processing is divided into chunks of 25 files per job. A batch of 2,000 images can therefore be distributed across approximately 80 manageable chunks rather than handled by one oversized job.
That provides a more practical foundation for retries, error isolation, and per-file failure reporting.
Users can retry individual files instead of starting the entire process again.
The takeaway: queues aren’t just a performance optimization. For workloads like this, they’re part of the product design.
- Upload validation: never trust the browser A file extension doesn’t prove what a file actually contains.
A file named product.jpg isn't necessarily a JPEG. Likewise, a client-supplied MIME type isn't a security guarantee.
AssetOps validates uploaded files using content inspection with PHP’s finfo, rather than relying solely on information supplied by the browser.
The application supports JPG, PNG, WebP, GIF, AVIF, HEIC, and TIFF inputs, subject to the capabilities of the configured processing environment.
This is a small implementation detail, but small details like this matter when you’re accepting files from users.
- Make infrastructure configurable, not hard-coded A self-hosted application should be usable in different environments without requiring developers to modify application code for every deployment.
AssetOps uses configurable image-processing and storage options.
For image processing, Intervention Image provides a common interface for supported drivers such as GD and libvips.
For storage, the application can use local storage or an S3-compatible configuration.
The principle is simple: deployment-specific decisions belong in configuration wherever practical.
A small deployment shouldn’t need the same infrastructure as a high-volume production environment. Keeping these concerns configurable makes the application easier to adapt.
Of course, actual performance depends on the server, image sizes, available memory, and selected processing driver.
- SEO-friendly filenames without the manual cleanup Image optimization isn’t only about file size.
For e-commerce stores, descriptive filenames also help keep product assets organized and provide useful context for search engines.
AssetOps supports customizable filename templates, for example:
{brand}-{product}-{color}-{index}
A filename might become:
acme-running-shoes-black-001.webp
A dedicated filename-planning service handles slug generation and collision-safe indexing to avoid duplicate names within the generated output.
Users can also rename individual files or make bulk changes through the interface.
Become a Medium member
It’s a relatively small feature, but it eliminates a tedious part of preparing large product catalogs.
- Privacy, secure downloads, and usage tracking There are three additional concerns that are easy to overlook when building image-processing software.
Metadata privacy
Images can contain more information than their visible pixels. GPS coordinates and other EXIF, IPTC, or XMP metadata may reveal details users don’t intend to publish.
AssetOps provides metadata-removal options to help reduce that risk. The resulting files should still be verified against the application’s configured stripping behavior and the desired privacy requirements.
Secure downloads
Processed files are delivered through signed, expiring download URLs rather than relying on permanently public file links.
The configured expiration limits how long a generated download link remains valid.
Usage tracking
The application records processing activity and tracks usage against configurable limits.
Users can review usage statistics and savings, while administrators can manage quotas and monitor platform activity.
Together, these features help turn an image-processing utility into a more complete application.
- The admin dashboard: the difference between a script and a product A working processing pipeline is only part of the job.
AssetOps also includes:
User registration, authentication, and password recovery.
Projects for organizing processing work.
Reusable presets for common optimization settings.
Batch and per-file management.
Usage statistics and configurable quotas.
Account settings and account deletion.
Administrative user management and quota overrides.
Failed-job monitoring.
Gumroad license activation.
Optional AI-generated ALT-text suggestions through an OpenAI integration.
None of these features is particularly exciting in isolation. But without them, users are left with a processing engine instead of a usable application.
The dashboard, error states, download workflow, and administration tools are what connect the underlying services into a complete user experience.
- Thirty-two automated tests — and why they matter The backend includes 32 automated tests covering important application workflows, including:
Authentication.
Batch upload, processing, and download.
File-content validation.
Quota enforcement.
Projects and presets.
License activation and deactivation.
Download-token expiration.
SEO filename generation.
The frontend is built using strict TypeScript settings, with type checking included in the build process.
Tests don’t prove that every deployment scenario is flawless. They do provide a repeatable way to verify key behaviors and reduce the risk of breaking existing functionality during future development.
When evaluating a codebase, I’d rather see meaningful tests around the core workflows than a long feature list with no verification behind it.
What I learned building AssetOps Images
A few principles stood out during development.
- Design for failure, not just the happy path.
Large batches will encounter invalid files, processing errors, and interrupted jobs. Independent jobs and retryable operations make those failures easier to manage.
- Keep deployment choices configurable.
Storage drivers, processing engines, and other infrastructure settings shouldn’t require unnecessary code changes.
- Treat security as part of the workflow.
Upload validation, authorization, quotas, and expiring downloads aren’t optional extras when users are uploading and processing files.
- Don’t stop when the core feature works.
Authentication, projects, presets, administration, usage reporting, and useful error messages are what make the application practical to use.
- Build the entire workflow, not just the impressive part.
Converting an image is easy. Getting thousands of images from upload to a reliable, organized download is the actual engineering challenge.
Want the complete source code?
AssetOps Images is available as a complete source-code product.
The package includes the Laravel backend, React and TypeScript frontend, database migrations, seeders, demo data, development setup instructions, API documentation, and a launch-and-test guide.
It’s intended for developers, agencies, e-commerce teams, and builders who want to explore, customize, or deploy a self-hosted image optimization application instead of starting from an empty repository.
Get AssetOps Images here:
→ View AssetOps Images on Gumroad
If you’re building a Laravel application that handles uploads, background processing, or large batches of files, I’d also be interested to hear how you’re approaching job retries, storage, and processing limits.
Tags: Laravel, PHP, React, TypeScript, Image Optimization, WebP, AVIF, Software Architecture, Side Projects, SaaS Development