SQIP: SVG-Based LQIP Placeholders Built From a Plugin Pipeline
"SQIP" (pronounced \skwɪb\ like the non-magical folk of magical descent) is a SVG-based LQIP technique.
At a glance
- What is it?
- SQIP is a TypeScript image converter that turns photos into tiny SVG placeholders through composable plugins. It is aimed at front-end engineers who care about lazy-loading perceived performance, and it is still on a 1.0 beta line.
- Who is it for?
- Adopt SQIP if you already generate responsive images in a Node build step and want the placeholder step to be scriptable rather than manual. Skip it if you need a stable non-beta API, or if your build runs on a non-64-bit host and you cannot install Go and primitive yourself.
- Can I use it commercially?
- Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap SQIP fills between a blurred JPEG and a real image
A lazy-loaded image leaves a hole in the layout until the network delivers it. The common fix is a low quality image placeholder: a very small file, stretched across the final box, swapped out when the full image arrives. SQIP takes that idea and produces the placeholder as SVG instead of a second raster file. The README describes it as "a SVG-based LQIP technique" and lists the intended uses plainly: create very small image previews to improve lazy loading, convert images into abstract representations, or batch convert and resize pixel and vector images. The audience is therefore narrow but specific. You are building a site or a pipeline where images are already processed by Node, and you want the placeholder generated by the same job rather than by a designer exporting a blurred copy by hand. It is not a general image CDN and it is not a runtime library that swaps placeholders in the browser. It produces files and result objects; what you do with them is your problem.
How the plugin pipeline turns a photo into an SVG
SQIP is a monorepo. The repository root is a private workspace package named sqip-monorepo, with packages under packages/ and bundler integrations under integrations/. The core package is sqip, and everything else is a plugin you install separately. The README states that you need the core plugin plus all the plugins you want to use, naming sqip-plugin-primitive, sqip-plugin-svgo and sqip-plugin-data-uri as examples. So the data flow is: input image goes in, each configured plugin transforms the working result in order, and the final result object comes out. That object carries a content buffer holding the SVG, plus metadata with originalWidth, originalHeight, width, height, type, and a palette of six Vibrant swatches. The palette is not decoration; a plugin can use those colors. The data-uri plugin appends dataURI and dataURIBase64 fields to the metadata, which is what you would paste into an img src or a CSS background. Because plugins can attach their own metadata, the result shape is not fixed by the core. That is the design bet: a small core, and behaviour that lives in separately versioned packages. It means the interesting decisions (how many primitives, which SVG optimizer, whether to inline) are configuration, not code.
Installing SQIP and generating a first placeholder
The README requires Node.js 20 or newer and a 64-bit OS. The most common plugin, sqip-plugin-primitive, ships with a 64-bit executable for the three major operating systems, so on a normal machine you do not need Go. Install the core package and the plugins you want together:
npm install sqip sqip-plugin-primitive sqip-plugin-svgo sqip-plugin-data-uriFrom there the Node API is asynchronous. A minimal call takes an input path and an output path, and the README shows processing a whole folder with default settings:
import { sqip } from 'sqip'
import { resolve } from 'path'
const folderResults = await sqip({
input: resolve(__dirname, 'images/originals'),
output: resolve(__dirname, 'images/previews')
})What you get back is an array of result objects when the input is a folder, or a single object for one image. If you want to change how the placeholder looks, you pass a plugins array where each entry is either a string or an object with a name and an options bag. The README's example runs primitive with numberOfPrimitives set to 8 and mode set to 0, then SVGO with defaults:
const pluginResults = await sqip({
input: resolve(__dirname, 'images/originals'),
output: resolve(__dirname, 'images/previews'),
plugins: [
{ name: 'sqip-plugin-primitive', options: { numberOfPrimitives: 8, mode: 0 } },
'sqip-plugin-svgo'
]
})There is also a CLI, installed globally as a separate package:
npm install -g sqip-cliThe CLI help is only useful when you name the plugins, because plugin options are registered by the plugins themselves. The README's own example is:
sqip -h -p primitive -p blur -p svgoRunning that should print the shared options (input, output, width, silent, parseable-output) plus whatever primitive, blur and svgo contribute. If a plugin option is missing from that output, the plugin is not resolving, and that is the first thing to check before debugging the image itself.
The beta line, the 64-bit assumption and the plugin coupling
Three constraints deserve attention before you wire SQIP into a build. First, the release history is short and unsettled. The most recent release listed is [email protected] from 2026-03-03, and before that [email protected] from 2022-05-09. A four-year gap between alpha and beta, followed by a beta, means the API you read about today may still move. The README points v0 users at a MIGRATION.md file, which confirms that the project has already broken compatibility once. Second, the 64-bit requirement is a real deployment boundary, not a footnote. On a non-64-bit host, or if you want a newer primitive than the bundled binary, the README tells you to install Go and primitive with go get -u github.com/fogleman/primitive, then add the binary path to your environment. On macOS that means editing /etc/paths with the full path, not a tilde. That is a meaningful amount of setup for a placeholder generator, and it is the kind of thing that breaks inside a minimal container image. Third, because the pipeline is plugin-based, a change in one plugin version changes your output. Pinning sqip alone is not enough.
Where SQIP is the wrong tool
SQIP is a build-time converter, not a serving layer. If you want placeholders generated on demand at request time, with caching and content negotiation handled for you, this is the wrong shape of tool: it writes files or returns buffers, and you own the hosting. It is also a poor fit if your placeholders must be photographic. The primitive plugin reconstructs an image from geometric shapes, which is why the project's own demo compares plugin output side by side and why the README lists "do art" as a use case. That aesthetic is deliberate, but it is not a blur. If your design calls for a soft, faithful preview, a plain resized and blurred JPEG is simpler and has no plugin graph to maintain. Finally, if your team cannot take a beta dependency in the image pipeline, the version history above is the deciding fact, not the feature list.
How SQIP differs from a plain blurred thumbnail
The obvious alternative is to skip SQIP and generate a tiny raster placeholder with whatever image library you already use, then inline it as a base64 JPEG or PNG. The difference is in what gets transferred and how it scales. A blurred raster placeholder is a fixed-resolution bitmap: to look acceptable on a large hero image it needs enough pixels, and those pixels cost bytes. An SVG placeholder is resolution independent, and the primitive plugin's output is a small set of shapes rather than a grid of pixels. SQIP also gives you the palette in metadata, so the same run can produce a background color for the image box without a second tool. The trade-off runs the other way too. A blurred thumbnail is one library call with no plugin resolution, no 64-bit binary and no beta API. SQIP buys you a smaller, scalable placeholder and a configurable pipeline, and it charges you a plugin graph and a pre-1.0 dependency to get there.
Licence and the cost of keeping up
The repository is licensed under the Unlicense, which is a public-domain-style dedication rather than a permissive licence with attribution conditions. That removes the usual attribution and notice obligations, but it also means there is no warranty language to lean on, and some organisations have procurement rules that treat public-domain dedications differently from MIT or Apache-2.0. That is a policy question for your own legal reviewers, not something the project can settle for you. On upgrade cost, the repository layout tells you what maintenance looks like: it is a Lerna monorepo with workspaces for packages/*, integrations/* and demo-app, published through lerna publish with conventional commits, and a publish:beta script that pushes to the beta dist-tag. The root package.json pins Node >=20.0.0 and overrides sharp to ^0.34.5 and gifwrap to ^0.10.1. Practically, that means version bumps arrive per package, and the integrations directory exists because bundler integration is a separate concern from the core converter. Budget for reading changelogs across several packages, not one.
Editorial conclusion
Adopt SQIP if you already generate responsive images in a Node build step and want the placeholder step to be scriptable rather than manual. Skip it if you need a stable non-beta API, or if your build runs on a non-64-bit host and you cannot install Go and primitive yourself. Before committing, check the resolved version of the sqip package and the sqip-cli package, run sqip -h -p primitive -p blur -p svgo against one real photo to see which plugin options actually exist in that version, and confirm the Unlicense terms against your own release process.
Frequently asked questions
What Node.js version does SQIP require?
The README requires Node.js 20 or newer, and the root package.json sets engines.node to >=20.0.0. It also requires a 64-bit operating system for the bundled primitive plugin.
How do I install SQIP and its plugins?
Install the core package together with the plugins you want, for example npm install sqip sqip-plugin-primitive sqip-plugin-svgo sqip-plugin-data-uri. The CLI is a separate global package, sqip-cli, installed with npm install -g sqip-cli.
Why does sqip -h not show my plugin options?
The README states that you must specify plugins when using --help to see the available plugin options, and gives sqip -h -p primitive -p blur -p svgo as the example. Options are contributed by the plugins, so a plugin that is not named will not appear.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/axe312ger-sqip)