DEV Community

Cover image for How SleekCMS Handles Image Optimization (And Why You Probably Don't Need a Separate Service)
Yusuf B for SleekCMS

Posted on • Originally published at sleekcms.com

How SleekCMS Handles Image Optimization (And Why You Probably Don't Need a Separate Service)

The image problem in headless CMS

Image optimization is consistently one of the top contributors to poor Core Web Vitals scores. It's also one of the most tooling-heavy problems in a typical web project. The solutions — Cloudinary, Imgix, Next.js <Image>, <picture> with srcset — each solve the problem but add a dependency, a subscription cost, or a configuration surface.

For a headless CMS, the problem is specific: the CMS gives you image URLs. Serving those images at the right size, in the right format, for the right device is your problem. That usually means a third-party image CDN, a framework-level image component, or a manual transform layer wired up separately.

SleekCMS handles this at the platform level — image transformation via URL query parameters, built into every image asset.

The URL parameter API

Every image uploaded to SleekCMS has a CDN-backed URL. Appending query parameters transforms the image before delivery:

https://img.sleekcms.com/SITE_ID/IMAGE_ID.jpg?w=1200&h=600&fit=cover&fmt=webp&q=85
Enter fullscreen mode Exit fullscreen mode

No API call, no SDK, no configuration — just query parameters on the image URL.

Supported parameters:

Parameter Description Example values
w Width in pixels 400, 1200, 1920
h Height in pixels 300, 600, 1080
s Combined size shorthand (WxH) 1200x600, 400x300
fit Crop/resize mode cover, contain, fill
fmt Output format webp, jpg, png
q Quality (1–100) 85, 70, 40
dpr Device pixel ratio 2, 3
blur Gaussian blur radius 10, 20

The EJS helper functions

In SleekCMS templates, you don't typically construct these URLs by hand. The built-in helper functions handle it:

src(image, attr) — returns the transformed URL:

<img src="<%- src(item.cover, '1200x600') %>" alt="<%= item.cover.alt %>">
Enter fullscreen mode Exit fullscreen mode

img(image, attr) — renders a complete <img> element with correct src, alt, width, and height:

<%- img(item.cover, '1200x600') %>
Enter fullscreen mode Exit fullscreen mode

picture(image, attr) — renders a <picture> element with dark/light variant support and responsive source sets:

<%- picture(item.hero_background, { w: 1920, h: 800, fit: 'cover' }) %>
Enter fullscreen mode Exit fullscreen mode

svg(image, attr) — renders an inline SVG for icon fields:

<%- svg(item.logo, { class: 'h-8 w-auto' }) %>
Enter fullscreen mode Exit fullscreen mode

The attr parameter accepts either a "WxH" string for quick sizing or a full object for precise control:

<%- img(item.avatar, { w: 64, h: 64, fit: 'cover', class: 'rounded-full' }) %>
Enter fullscreen mode Exit fullscreen mode

Common patterns

Blog hero image — full width, WebP, high quality:

<%- img(item.cover, { w: 1200, h: 630, fit: 'cover', fmt: 'webp', q: 90 }) %>
Enter fullscreen mode Exit fullscreen mode

Thumbnail in a card grid — small, fast:

<%- img(post.cover, { w: 400, h: 250, fit: 'cover', fmt: 'webp', q: 75 }) %>
Enter fullscreen mode Exit fullscreen mode

Author avatar — small, circular (handled with CSS):

<%- img(item.author_avatar, { w: 64, h: 64, fit: 'cover', class: 'rounded-full' }) %>
Enter fullscreen mode Exit fullscreen mode

OG image for sharing — exact dimensions required by most social platforms:

<% meta({ property: 'og:image', content: src(item.seo.image, '1200x630') }) %>
Enter fullscreen mode Exit fullscreen mode

Blurred placeholder (low-quality image placeholder pattern):

<div style="background-image: url('<%- src(item.cover, { w: 40, blur: 10 }) %>')"
     data-src="<%- src(item.cover, '1200x600') %>">
</div>
Enter fullscreen mode Exit fullscreen mode

What this replaces

For most SleekCMS sites, the built-in transform API replaces:

  • Cloudinary or Imgix — a third-party image CDN subscription. The transform capabilities overlap significantly for standard web use cases.
  • Next.js <Image> component — if you're using the site builder, there's no Next.js in the stack. The img() helper covers the same functionality.
  • Manual srcset attributes — the picture() helper handles responsive image generation.
  • PostCSS image plugins — image optimization at build time. The transform URL handles it at request time, per device.

There are cases where a dedicated image CDN is still the right choice: complex focal-point cropping, facial detection, art direction with multiple editorial crops, high-volume media libraries that need advanced asset management. For standard web content — hero images, blog covers, team photos, product thumbnails — the built-in transform API covers the use case.

Core Web Vitals implications

Image optimization affects three of the Core Web Vitals metrics:

Largest Contentful Paint (LCP) — the hero image is often the LCP element. Serving it at the right size (not 4000px wide scaled down in CSS) and in WebP format typically yields the largest single LCP improvement available.

Cumulative Layout Shift (CLS) — the img() helper outputs width and height attributes, giving the browser the aspect ratio before the image loads. This prevents layout shift caused by images loading in without reserved space.

Interaction to Next Paint (INP) — less directly related to images, but serving smaller files reduces the bandwidth contention that delays interaction.

The URL parameter API makes it straightforward to serve the right image for every context — without a separate service, without a build-time step, and without per-framework configuration.

Top comments (0)