Stop Pre-Generating Image Thumbnails in Laravel — Do It…
    Neura MarketNeura Market/Stable Diffusion
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityStable DiffusionStable Diffusion
    DeepSeekDeepSeekCoPilotCoPilotMidjourneyMidjourney
    View All Directories
    OverviewPromptsBlogVideosGuidesCoursesCommunityModelsLoRAsComfyUI WorkflowsTrending
    Stable DiffusionBlogStop Pre-Generating Image Thumbnails in Laravel — Do It On-The-Fly Instead
    Back to Blog
    Stop Pre-Generating Image Thumbnails in Laravel — Do It On-The-Fly Instead
    backend

    Stop Pre-Generating Image Thumbnails in Laravel — Do It On-The-Fly Instead

    Vas May 7, 2026
    0 views

    Every Laravel project eventually hits the same wall: a designer asks for a new image size, and...

    Every Laravel project eventually hits the same wall: a designer asks for a new image size, and suddenly you're writing a migration, a queue job, and a Media Library conversion — just to serve a 400px thumbnail.

    There's a simpler way. Generate image variants on demand, cache the result permanently, and move on.

    That's exactly what laravel-imagepresets does.


    The Problem With Pre-Generated Thumbnails

    When you pre-generate image variants (the approach Spatie Media Library encourages by default), you pay upfront:

    • Storage costs for every variant of every image, even ones never viewed
    • Queue processing time on upload
    • Pain when design requirements change and you need to regenerate thousands of files
    • Complex seeding/migration logic for existing images

    On-the-fly processing flips this: you process an image the first time it's requested, cache the result, and never touch it again. The tradeoff is a slightly slower first request — which is usually invisible to users.


    What Is laravel-imagepresets?

    It's a Laravel package built on League/Glide that gives you:

    • A single /imagepreset route that handles all image transformations
    • Automatic caching to any Laravel filesystem disk (local, S3, GCS, FTP)
    • A clean API — helper function, Facade, and Blade directive
    • Named presets so you define sizes once and reuse them everywhere
    • Production-ready security: SSRF protection, allowlists, signed URLs, SVG sanitization

    Installation

    composer require fomvasss/laravel-imagepresets
    php artisan vendor:publish --tag=imagepresets-config
    

    The service provider is auto-discovered. No manual registration needed.


    Your First Image URL

    // Resize to 800px wide, convert to WebP
    $url = imagepreset_url('storage/images/photo.jpg', ['w' => 800, 'fm' => 'webp']);
    // → https://example.com/imagepreset?fm=webp&src=storage%2Fimages%2Fphoto.jpg&w=800
    

    On the first hit, Glide resizes and converts the image, stores it on your configured disk, and returns it with a one-year Cache-Control header. The next request? Pure cache — Laravel never runs.


    Named Presets: Define Once, Use Everywhere

    Hardcoding ['w' => 300, 'h' => 200, 'fm' => 'webp', 'fit' => 'crop'] everywhere is a maintenance headache. Named presets solve this.

    In config/imagepresets.php:

    'presets' => [
        'thumb'     => ['w' => 300, 'h' => 200, 'fm' => 'webp', 'fit' => 'crop'],
        'hero'      => ['w' => 1200, 'fm' => 'webp', 'q' => 85],
        'avatar'    => ['w' => 96,  'h' => 96,  'fm' => 'webp', 'fit' => 'crop'],
        'og_banner' => ['w' => 1300, 'h' => 650, 'fit' => 'fill-max', 'fm' => 'jpg', 'bg' => 'ffffff'],
    ],
    

    Then in your code:

    // String shorthand
    $url = imagepreset_url('photo.jpg', 'thumb');
    
    // Facade
    Imagepreset::url('photo.jpg', 'hero');
    
    {{-- Blade directive --}}
    <img src="@imagepreset('photo.jpg', 'thumb')" alt="Thumbnail">
    

    Need to override one param? Pass it alongside the preset name:

    // Use thumb preset but output JPG instead of WebP
    $url = imagepreset_url('photo.jpg', ['preset' => 'thumb', 'fm' => 'jpg']);
    

    Fit Methods Explained

    The fit parameter controls how the image fills the target dimensions. Choosing the wrong one is a common source of stretched or oddly-cropped images.

    FitUse when...
    cropYou need exact pixel dimensions (cards, avatars). Edges may be trimmed.
    containThe full image must be visible. No fill — transparent space is left.
    fillFull image visible, remaining canvas filled with bg color. May upscale.
    fill-maxLike fill but never upscales. Great for OG images and social banners.
    maxLike contain but never upscales beyond original size.
    stretchForces exact dimensions ignoring aspect ratio. Rarely a good idea.

    For OG images, fill-max is your friend:

    $url = imagepreset_url('post-image.jpg', [
        'w' => 1300, 'h' => 650,
        'fit' => 'fill-max',
        'fm' => 'jpg',
        'bg' => 'ffffff',
    ]);
    

    S3 / Remote Disk Support

    Just set the disk in your .env:

    IMAGEPRESET_DISK=s3
    IMAGEPRESET_PATH=imagepresets
    

    The package detects remote disks automatically. Glide processes the image locally, uploads the result to S3 via Flysystem, deletes the local temp file, and streams the response directly from S3. No extra code needed.


    Security Out of the Box

    Open image-resizing endpoints are a common attack surface. The package handles the main threats:

    Allowlists prevent arbitrary dimensions from being requested:

    'allowed_widths'  => [100, 200, 400, 800, 1200],
    'allowed_heights' => [100, 200, 400, 600],
    'allowed_formats' => ['webp', 'jpg', 'png'],
    

    SSRF protection blocks remote image sources that point to private IPs or localhost.

    Image bomb protection rejects files that exceed max_image_pixels (default: 150 Mpx).

    Signed URLs (optional) make it impossible to tamper with parameters:

    IMAGEPRESET_SIGNED_URL=true
    

    Once enabled, imagepreset_url() automatically generates HMAC-signed URLs. Changing any parameter returns 403.


    Race Condition Protection

    What happens when 50 users simultaneously request the same uncached image? Without protection, you'd process the same image 50 times.

    The package uses Cache::lock() to ensure only one process generates each variant. Set CACHE_DRIVER=redis for this to work correctly across multiple servers.


    Audit Log: Discover What Your Frontend Actually Needs

    Before locking down allowlists in production, you can enable audit logging in development to see exactly which params your frontend requests:

    IMAGEPRESET_AUDIT_LOG=true
    

    Then extract unique values from your logs:

    grep -oh '"w":[0-9]*' storage/logs/*.log | sort -u
    

    Use the findings to populate your allowlists before deploying.


    CDN and Nginx Caching

    Every response ships with:

    Cache-Control: public, max-age=31536000, s-maxage=31536000, immutable
    ETag: "<hash>"
    

    This makes it trivial to cache at the edge. The README includes ready-to-use configs for Nginx proxy cache and Cloudflare Cache Rules.

    To verify your cache is working:

    # Run twice — first should be MISS, second HIT
    curl -s -o /dev/null -D - "https://example.com/imagepreset?src=photo.jpg&w=800&fm=webp"
    

    Clearing the Cache

    # Clear all cached presets
    php artisan imagepresets:clear
    
    # Clear a specific remote disk
    php artisan imagepresets:clear --disk=s3 --path=imagepresets
    

    Requirements

    DependencyVersion
    PHP^8.1
    Laravel10 / 11 / 12 / 13
    league/glide^2.0 | ^3.0

    Optional: imagick extension for AVIF output and SVG rasterization.


    Wrapping Up

    If your project doesn't need the full power of Spatie Media Library — associations, conversions, responsive images — and you just want to serve the right image size without pre-generating everything, laravel-imagepresets is worth a look.

    Install it, define a few presets, drop @imagepreset() into your Blade templates, and you're done.

    composer require fomvasss/laravel-imagepresets
    

    → GitHub · Packagist


    Have questions or found a bug? Open an issue on GitHub.

    Tags

    backendlaravelperformancephp

    Comments

    More Blog

    View all
    Context bankruptcy: The case for strategic forgetting for AI Agentsai

    Context bankruptcy: The case for strategic forgetting for AI Agents

    Most of us have seen a coding agent fail to complete a task we know it can do. We just don't...

    J
    James O'Reilly
    Parallel Compliance Engine: Drive-to-Sheets Multi-Agent Orchestrationgooglecloud

    Parallel Compliance Engine: Drive-to-Sheets Multi-Agent Orchestration

    When building Generative AI applications, developers often encounter a massive bottleneck: sequential...

    A
    Aryan Irani
    Is It Ethical to Post and Ask About Circuits on Dev.to?discuss

    Is It Ethical to Post and Ask About Circuits on Dev.to?

    I’ve been thinking about sharing some electronic circuit posts on Dev.to — small circuits, DIY...

    C
    codebunny20
    The One-Click Exporter: AI Studio Antigravity, Probed to Its Limitsagents

    The One-Click Exporter: AI Studio Antigravity, Probed to Its Limits

    What nobody tells you about exporting your multi-agent prototype to a local workspace. Every...

    L
    leslysandra
    Guarding the till while autonomous data agents do the diggingagenticarchitect

    Guarding the till while autonomous data agents do the digging

    Autonomous agents are genuinely good at answering messy business questions. Give one an LLM and a set...

    S
    Sireesha Pulipati
    Return on Attention: Why AI Code Reviews Are Wearing Us Outai

    Return on Attention: Why AI Code Reviews Are Wearing Us Out

    PR volume went up, ticket quality didn't, and the gap got filled with LLMs on both sides of the review: bots reviewing, bots replying, bots occasionally arguing with bots about priorities that only existed in a teammate's head. Our CEO named the actual problem, and it's bigger than code review.

    C
    christine

    Stay up to date

    Get the latest Stable Diffusion prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for Stable Diffusion and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.

    Ready-made automations for this

    Workflows from the Neura Market marketplace related to this Stable Diffusion resource

    • Generating Image Embeddings via Textual Summarisationn8n · $18.99 · Related topic
    • Automate Viral YouTube Titles & Thumbnails (FLUX.1 + Apify)n8n · $24.99 · Related topic
    • YouTube SEO: Generate Content & Thumbnails from Scripts with GPT-4o & Runwayn8n · $24.99 · Related topic
    • Generating Keywords & Search Volumes via Google Ads APIn8n · $18.99 · Related topic
    Browse all workflows