uqr encodes a QR code once and renders it four ways, from a terminal to an SVG
Generate QR Code universally, in any runtime, to ANSI, Unicode or SVG.
At a glance
- What is it?
- uqr is a small TypeScript package that turns text or binary data into a QR code and renders it as ANSI colour, Unicode blocks, a compact two-row Unicode form or SVG, with no dependencies and tree-shaking support. It is still on a 0.1.x version line, so the API is young.
- Who is it for?
- uqr fits projects that need a QR code in a place most libraries do not reach, a terminal, a CLI, a chat message, a server-rendered page or a runtime with no native modules, and it fits bundles that care about size, since the package ships no dependencies and marks itself side-effect free. It is the wrong choice if you need barcode formats beyond QR, or if you want styled codes with logos, gradients or dot patterns, since the README points at etiket for that.
- Can I use it commercially?
- Yes. MIT 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?
- Activity is slowing. The repository last received commits 6 months 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 October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One encoder, four renderers, no dependencies
uqr is a TypeScript package for generating QR codes, and the README states its scope in a single line: generate QR Code universally, in any runtime, to ANSI, Unicode or SVG. It is an ES module with zero dependencies and is described as tree-shakable.
The design is a clean two-layer split. The encoding layer turns data into a matrix, and the rendering layer turns that matrix into a presentation format. There is an encode function and four renderers on top of it: renderANSI, renderUnicode, renderUnicodeCompact and renderSVG.
That separation is what makes the package useful in places a typical QR library does not reach. A server that has to return an SVG, a CLI that has to print something a phone camera can read, and a script that needs to embed a code in a log line all use the same encoder and differ only in the renderer.
The zero dependency claim matters more than it might sound for a package like this. QR encoding is not a trivial algorithm, but the README credits the generation algorithm to a modified version of nayuki/QR-Code-generator by Project Nayuki, so the heavy lifting is imported by attribution rather than reimplemented. What you install is the TypeScript port and the renderers.
The tree-shaking side is supported by the package metadata, which sets sideEffects to false, and the README calls the package tree-shakable. A CLI that only needs renderANSI should not pay for the SVG renderer.
encode hands back a boolean matrix, a version and a size
The encoder is the only part you need if you are writing your own renderer, and its return value is deliberately plain data:
import { encode } from 'uqr'
const {
data, // 2D array of boolean, representing the QR Code
version, // QR Code version
size, // size of the QR Code
} = encode(text, options)The README describes encode as encoding plain text or binary data into a QR Code represented by a 2D array. The array holds booleans, one per module, and the other two fields tell you which QR version was chosen and what the resulting size is.
Returning booleans rather than characters is the right call for a package that renders to several formats, because a renderer then decides what a true module looks like: a filled block, a background colour, an SVG rectangle. It also means you can implement a format the package does not ship, such as a PNG encoder or a half-block renderer for a browser, without parsing any string output.
The options argument is the same options object the renderers accept, which is why the renderers can be used as a shortcut for encode plus render in one step.
Terminal output: coloured ANSI, block characters, and the two-row form
Three of the four renderers exist for terminals, and each solves a different constraint.
renderANSI produces an ANSI coloured string, which is the readable option when the terminal supports colour. The README example shows the options that matter:
const ansi = renderANSI('https://192.168.1.100:3000', {
// Error correction level
ecc: 'L',
// Border width
border: 2,
})
// display QR Code in terminal
console.log(ansi)The error correction level and the border width are the two knobs that matter for a terminal code. A lower error correction level means fewer redundant modules and a denser code, and the border is the quiet zone that scanners need around the code to recognise it.
renderUnicode uses block characters per pixel, by default █ for black and ░ for white, and both are configurable:
const string = renderUnicode(text, {
blackChar: '█',
whiteChar: '░',
// ...other options
})renderUnicodeCompact is the one that solves a real terminal problem. The README says it renders the QR code with two rows into one line using ▀, ▄, █ and a space, and that it is useful when you want to display a QR code in a terminal with limited height. Half-block characters let two vertical pixels share one line of text, which roughly halves the height of the output.
The README notes that the CLI renders are inspired by qrcode-terminal, so the visual conventions come from an existing terminal tool rather than being invented here.
SVG for the web, and why a separate renderer exists
renderSVG returns an SVG string for the same matrix:
import { renderSVG } from 'uqr'
const string = renderSVG(text, options)A dedicated SVG renderer is worth having rather than bolting one onto a generic matrix output, because SVG is the format that survives the trip from a server to a browser cleanly. It scales, it can be styled with CSS, it prints well, and it does not need a canvas or a font to be embedded.
Returning a string rather than a DOM element is the other decision that matters here. renderSVG produces text, not a live object, so it can be used in a template, sent over an API, cached, or written to a file, and it works in a runtime with no DOM at all, which is the point of a package that claims to work in any runtime.
Since the matrix comes from encode, a caller can also take the data array and produce an SVG with different sizing or colour choices by hand, though the built-in renderer is the faster route for the common case.
Installing with npm, yarn or pnpm
The README gives the three package manager invocations and nothing else, so installation is genuinely one step whichever tool you use:
# Using npm
npm install uqr
# Using yarn
yarn add uqr
# Using pnpm
pnpm add uqrThe package metadata shows what you get. The package is named uqr, its version field reads 0.1.3, it is an ES module with a type field of module, and it ships both import and require entry points through the exports map, with dist/index.mjs and dist/index.cjs. The published files field contains only dist, so no source or test files land in your node_modules.
The main and module fields both point at dist/index.mjs, and the types field points at dist/index.d.ts, with typesVersions mapping to the dist directory for older TypeScript resolution modes. So the TypeScript definitions ship with the package.
The declared package manager is [email protected], and the repository is a pnpm workspace with a pnpm-lock.yaml and a pnpm-workspace.yaml at the root.
The alternative the README names, and where it differs
The README has an Alternatives section, and it points at etiket, described as a zero-dependency barcode and QR code SVG generator with 20+ formats, including 1D barcodes, QR, Data Matrix, PDF417 and Aztec, with styled QR codes using dot types, gradients and logos, tree-shakeable, and a CLI tool.
The difference in approach is clear from those descriptions. uqr stays inside the QR code format and specialises in output targets, with four renderers for terminals, SVG and raw data, and no styling features. etiket covers a much wider set of symbologies and adds visual styling, at the cost of a bigger surface.
So the choice is format coverage and appearance against minimalism. If you need to render a Code 128 barcode or a PDF417, uqr cannot do it. If you want a QR code with a logo in the middle and a gradient, the styling features are not in uqr's documented options.
On the size axis the two look alike, since both are described as zero dependency and tree-shakable, so bundle size is not a deciding factor between them. Runtime target is also similar, since both are aimed at generating output rather than scanning.
The honest summary is that uqr is the smaller, more specialised tool for one symbology, and etiket is the broader one when format variety or styled output matters.
A 0.1.x package with a modern build setup
The version line is where caution belongs. The published version is 0.1.3, released on 2026-04-03, and the two earlier tags are v0.1.2 from 2023-08-16 and v0.1.1 from 2023-08-15. The last push to the repository was on 2026-04-03, the same day as the latest release.
A 0.x version carries the usual signal in the JavaScript ecosystem: the package is usable and published, but the maintainers have not committed to a stable API, and minor releases may carry breaking changes. Anyone integrating uqr into a long-lived product should pin an exact version rather than a caret range, and should read the changelog before upgrading.
The tooling around the code is modern and tells you how the project is developed. The build script runs unbuild, dev runs unbuild --stub, tests run with vitest, linting with eslint through the antfu eslint config, and typecheck runs tsc --noEmit. Releases go through bumpp and npm publish, and a simple-git-hooks configuration runs lint-staged on commit, where lint-staged applies eslint --fix to staged files.
The repository root also has a play/ directory with a run script invoked through tsx, which looks like a scratch area for trying renders, and a build.config.ts that configures the bundler. The license is MIT.
Editorial conclusion
uqr fits projects that need a QR code in a place most libraries do not reach, a terminal, a CLI, a chat message, a server-rendered page or a runtime with no native modules, and it fits bundles that care about size, since the package ships no dependencies and marks itself side-effect free. It is the wrong choice if you need barcode formats beyond QR, or if you want styled codes with logos, gradients or dot patterns, since the README points at etiket for that. Verify first which version you are pinning, because the published line is 0.1.3 and the earlier tags are 0.1.1 and 0.1.2, and note that the last push to the repository was on 2026-04-03, so check whether the API you read about is still the API in the version you install.
Frequently asked questions
What output formats can uqr produce?
uqr can render a QR code as an ANSI coloured string, as a Unicode string with block characters per pixel, as a compact Unicode form that fits two rows into one line, or as an SVG string. The encode function returns the raw matrix if you want to render it yourself.
How do I install uqr?
The README lists three commands: npm install uqr, yarn add uqr and pnpm add uqr. The package is published on npm as uqr, ships as an ES module with both import and require entry points, and includes TypeScript definitions.
How do I render a QR code in a terminal with uqr?
Use renderANSI for a coloured string, renderUnicode for block characters per pixel with configurable black and white characters, or renderUnicodeCompact when the terminal has limited height, since it renders two rows into one line with upper and lower half block characters.
Is uqr suitable for barcodes other than QR codes?
No, uqr covers QR codes. The README names etiket as an alternative that handles 20+ formats including 1D barcodes, Data Matrix, PDF417 and Aztec, and adds styled QR codes with dot types, gradients and logos.
Is the uqr API stable?
The published version is 0.1.3, released on 2026-04-03, after 0.1.2 and 0.1.1 in August 2023. On a 0.x line the API can still change between minor releases, so pin an exact version and read the changelog before upgrading.
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/unjs-uqr)