Aerial view of woodland

Unpic 1.0

Sun Jan 19 2025

After two years of development, I’m excited to announce the first stable release of Unpic.

Since starting work on Unpic, I’ve been astounded by the response from the community. With over 50,000 npm downloads per week, 1500 stars and a growing number of contributors on GitHub, it’s clear that developers really need a good way to handle images. To jump straight in, see the guide to upgrading to v1.

Meet Unpic

If you’re new to Unpic, it is the best way to display images on the web. With components for ten different frontend frameworks and 26 image hosts, most sites can have fast, responsive images with very little effort. A family of image components make it as easy to create a responsive image as it is to use an <img> tag. It uses your existing image CDN or CMS with no additional configuration, generating the correct HTML tags with all the right attributes, and lightweight styles to make the image resize responsively. See how to use Unpic for more details of the syntax for different frameworks, and the HTML it generates.

What’s new in Unpic 1.0

Most of the changes are because of a new, simplified approach to handling individual image CDNs and providers in the base Unpic library. This is designed to make Unpic more flexible, efficient and modular. It also introduces support for type-safe custom operations and options for each provider.

Provider operations

Supported frameworks: All except webc and lit.

The new operations property allows you to specify custom operations for each provider. Many image CDNs support dozens of custom operations. Previously these were hard to use with Unpic. The new operations property gives type-safe support for all supported features of each provider. This works even if you have images from multiple providers in the same component, as you can specify options for each provider separately.

Auto-complete of provider operations
<Image
src={imgUrl}
operations={{ imgix: { flip: "h" }, bunny: { flop: true } }}
/>

The operations are all type-safe, with JSDoc comments and TypeScript definitions. This means you can get autocompletion and type checking.

Provider options

Supported frameworks: All except webc and lit.

The new options property allows you to specify custom options for each provider. This is similar to the current cdnOptions property, but with type-safe support for all options of each provider. This allows you to specify options such as account IDs and domains for each provider.

Auto-complete of provider options

Fallback providers

Supported frameworks: All. The astro and nextjs frameworks default to the framework’s image provider as fallback.

The new fallback property lets you specify a fallback provider for each image. This allows you to use auto-detection for image CDNs as now, but also specify a fallback provider for local images and images from unknown providers. This is useful if you have a mix of images from different sources, and want to ensure that all images are handled correctly. For example, you may have a Sanity blog hosted on Netlify. Sanity hosts all images on Imgix (a supported provider), but you may also some images from third-parties or your own server. You can specify Netlify as the fallback provider so that it uses the Netlify Image CDN for all images that are not from Sanity or another supported provider. This will be all handled automatically.

Auto-completion of fallback provider

Base component

Supported frameworks: All except webc, lit and angular.

Previously, the Image and Source components always loaded support for every provider, even if you specified a single provider or custom transformer. This is fine if you are using auto-detection, but many people wanted to use the components in a more custom or modular way. The new base components allow you to use the Unpic component without any of the automatic detection and transform logic. You can provide your own transformer, or use a single, tree-shakable provider import. This is useful if you are using a single provider, or if you are building a custom component based on Unpic.

// Import from the `/base` subpath
import { Image } from "@unpic/react/base";
// Import the transformer for the provider you are using
import { transform } from "unpic/providers/imgix";
export const Hero = () => (
<Image
src="https://images.unsplash.com/photo-1733626631376-214e024f5520"
transformer={transform}
operations={{ rot: 90 }}
width={800}
height={400}
/>
);

The operations and options properties are still type-safe and inferred from the transformer, and you don’t need to specify the provider name in the operations object.

How to use Unpic

This is how to use the Image component from @unpic/react:

import { Image } from "@unpic/react";
export const MyImage = () => (
<Image
src="https://res.cloudinary.com/demo/image/upload/dog"
width={600}
height={300}
alt="Dog"
/>
);

This generates the following HTML:

<img
alt="Dog"
loading="lazy"
decoding="async"
sizes="(min-width: 600px) 600px, 100vw"
style="object-fit:cover;max-width:600px;max-height:300px;aspect-ratio:2;width:100%"
srcset="
https://res.cloudinary.com/demo/image/upload/w_600,h_300,f_auto,c_lfill/dog 600w,
https://res.cloudinary.com/demo/image/upload/w_640,h_320,f_auto,c_lfill/dog 640w,
https://res.cloudinary.com/demo/image/upload/w_750,h_375,f_auto,c_lfill/dog 750w,
https://res.cloudinary.com/demo/image/upload/w_828,h_414,f_auto,c_lfill/dog 828w,
https://res.cloudinary.com/demo/image/upload/w_960,h_480,f_auto,c_lfill/dog 960w,
https://res.cloudinary.com/demo/image/upload/w_1080,h_540,f_auto,c_lfill/dog 1080w,
https://res.cloudinary.com/demo/image/upload/w_1200,h_600,f_auto,c_lfill/dog 1200w
"
src="https://res.cloudinary.com/demo/image/upload/w_600,h_300,f_auto,c_lfill/dog"
/>

Look at that puppy!

Dog

No configuration is needed at all. Unpic detects that this is a Cloudinary URL, and uses the Cloudinary transformer to generate the correct image sizes and formats. It also generates the correct srcset and sizes attributes for the image, and adds the correct loading and decoding attributes to ensure the image is loaded quickly and responsively. The resulting image is responsive and fast, but as easy to use as a basic img tag.

Supported frameworks and providers

Unpic supports ten different frontend frameworks, and 26 different image providers. The supported frameworks are:

Angular • Astro • Lit • Preact • Qwik • React • Solid • Svelte • Vue • WebC

Here are a few examples of how to use Unpic with different frameworks:

Astro

---
import { Image } from "@unpic/astro";
---
<Image
src="https://res.cloudinary.com/demo/image/upload/dog"
width={600}
height={300}
alt="Dog"
/>

Solid

import { Image } from "@unpic/solid";
import type { Component } from "solid-js";
const App: Component = () => {
return (
<Image
src="https://cdn.shopify.com/static/sample-images/garnished.jpeg"
width={800}
height={600}
alt="Tasty food"
/>
);
};

Svelte

<script>
import { Image } from "@unpic/svelte";
</script>
<Image
src="https://bunnyoptimizerdemo.b-cdn.net/bunny7.jpg"
width={800}
height={600}
alt="Bunny"
/>

Vue

<script setup lang="ts">
import { Image } from "@unpic/vue";
</script>
<template>
<Image
src="https://images.unsplash.com/photo-1674255909399-9bcb2cab6489"
width="600"
height="600"
alt="Beach"
/>
</template>

To see more examples from all supported frameworks, check out the docs.

What’s next?

If you’ve been using Unpic 0.x, check out the guide to upgrading to v1. Otherwise, get started with Unpic today.

I’m excited to see what people build with the new version Unpic. Let me know how you’re using it, and what you’d like to see in future versions. If you’d like to contribute, check out the contributing guide.