retail-print-kit

An alternative to escpos and node-thermal-printer, and how to migrate

The escpos package has not had a stable release in years, and its USB adapter is still an alpha. node-thermal-printer is maintained but stops at ESC/POS and Star Line text. If you need Star TSP100, label printers, templates, previews or printer status, retail-print-kit covers them in one package.

Comparison

retail-print-kitescposnode-thermal-printer
Epson ESC/POS and compatiblesyesyesyes
Star Line Modeyesnoyes
Star raster-only (TSP100 / TSP143)yesnono
Label printers (ZPL, TSPL, EZPL)yesnono
Printer profilesyesnono
JSON templates with data bindingyesnono
HTML / PNG / SVG previewyesnono
Printer status and model detectionyesnopartly
TypeScript typesbuilt incommunitybuilt in
Packages a plain install adds (measured Oct 2026)4667

Migrating from escpos

The builder keeps the escpos method names, so most receipt code does not change.

Before:

const escpos = require('escpos');
escpos.USB = require('escpos-usb');
const device = new escpos.USB();
const printer = new escpos.Printer(device);

device.open(() => {
  printer.align('ct').style('b').size(2, 2).text('MY STORE')
    .tableCustom([{ text: 'Coffee', align: 'LEFT', width: 0.7 }, { text: '$2.50', align: 'RIGHT', width: 0.3 }])
    .cut().cashdraw().close();
});

After:

const { Printer, profiles } = require('retail-print-kit');
const { UsbTransport } = require('retail-print-kit/usb');
const printer = new Printer(new UsbTransport(), profiles['epson-tm-t88']);

await printer.open();
printer.align('ct').style('b').size(2, 2).text('MY STORE')
  .tableCustom([{ text: 'Coffee', align: 'LEFT', width: 0.7 }, { text: '$2.50', align: 'RIGHT', width: 0.3 }])
  .cut().cashdraw();
await printer.close();

What changes:

escposretail-print-kit
new escpos.USB(), escpos.Network(host), escpos.Serial(port)UsbTransport, NetTransport, SerialTransport
device.open(callback)await printer.open()
printer.close() sends and closesawait printer.close() (returns a promise)
font('a')setFont('a')
qrimage(text, opts, cb)qr(text, { size }), no callback
image(img, density) with escpos.Image.loadimage(await loadImage(file, { width }))
options { encoding }the profile's code page

The global USB detach listener that escpos-usb leaks is gone: listeners are attached on open and removed on close.

Migrating from node-thermal-printer

node-thermal-printerretail-print-kit
new ThermalPrinter({ type: PrinterTypes.EPSON, interface: 'tcp://192.168.1.50' })new Printer(new NetTransport('192.168.1.50'), profiles['epson-tm-t88'])
println(text)text(text)
alignCenter(), alignLeft(), alignRight()align('ct'), align('lt'), align('rt')
bold(true)style('b'), back with style('normal')
setTextSize(h, w)size(w + 1, h + 1)
tableCustom([...])tableCustom([...])
printQR(text), code128(data)qr(text), barcode(data, 'CODE128')
openCashDrawer()cashdraw()
cut(), partialCut()cut(), cut(true)
await execute()await close() or await flush()

Check before you ship

npx retail-print-kit test --net 192.168.1.50 --profile epson-tm-t88

prints a test page and the printer status.

Related: print a receipt, Star TSP100, labels.

Install

npm install retail-print-kit

All guides · Designer · npm · GitHub