If you run one warehouse, on one operating system, with people who already administer Linux boxes, self-host your print server. CUPS is free, it has been doing this since 1999, and a Raspberry Pi next to the printer will outlast the vendor you were considering.
The decision gets hard when the printers are not yours. That is the actual axis, and it is not the one most build-versus-buy posts argue about. Almost nobody fails at self-hosting a print server because the software was hard. They fail because they underestimated shipping a signed desktop agent to a thousand machines they do not administer, and because they never built the tooling to answer "did order 4471 print, and if we retry, will there be two labels."
Self-hosting is having a good year. "Cloud in a Bottle: making self-hosting accessible to everyone" hit 651 points on Hacker News on September 6, 2026, and the enthusiasm is earned. Print is one of the more self-hostable things in a stack. This post says where that stops being true, written by people who sell the alternative, which you should weigh accordingly.
A print server is four components, and only one of them is a print server
The phrase covers more than people expect. Saying "we will self-host a print server" commits you to build or operate:
- A spooler. CUPS on Linux and macOS, the Windows print spooler on Windows. This is the part you do not build. It handles queues, drivers, and handing bytes to hardware.
- A queue with durability. Something that accepts a job from your application, persists it, and survives a restart with the job intact. Postgres is fine.
- An agent. Code running on, or with network reach to, the machine attached to the printer. Where most of the real work lives.
- A control plane. What your application talks to: authentication, routing a job to the right machine, knowing whether that machine is alive, exposing status.
If the printer is in your own rack or on your own LAN, components 3 and 4 collapse to almost nothing. Your application talks to CUPS over IPP, or shells out to lp, and you are done in an afternoon. That configuration is good, and we have talked people out of buying from us because it described their situation.
If the printer is in a customer's building, behind their NAT, on a laptop that sleeps, components 3 and 4 are the project.
The build list is longer than it looks
This is the scope for a multi-site, multi-customer print path. Every row is something we built, so the right-hand column is not speculation.
| Component | Minimum viable | What makes it expensive |
|---|---|---|
| Agent for two operating systems | A Node process launched at login | macOS and Windows raw printing are different code paths. macOS goes through CUPS with a raw option; Windows needs a native spooler helper |
| Code signing and notarization | Apple Developer and an EV certificate | Certificate renewals, notarization failures on release day, Windows SmartScreen reputation on a fresh binary |
| Auto-update | An updater library | Never installing mid-job, offering a postpone, and preserving device identity across the update |
| Outbound transport and auth | A WebSocket and a bearer token | Device-bound credentials, revocation, half-open socket detection, reconnect without a stampede |
| Durable queue | A jobs table | Leasing so two workers cannot dispatch the same job, and expiry so stale jobs do not print tomorrow |
| Idempotency at both ends | A unique index on a key | The agent needs its own durable record of finished jobs, or a redelivery after a crash prints twice |
| Tenant isolation | A customer_id column |
Per-tenant credentials, enrollment bound to a tenant, suspend without delete, delegated support access with a trail |
| Support tooling | Reading the database | A view an on-call person can use at 2am to answer whether a specific label printed |
| On-call | Someone's phone | Printing fails during shifts, and a pack bench that is not printing stops a shipping operation |
Teams consistently omit the first three rows from the estimate. Shipping a desktop application is a discipline, not a task. Our own version 1.0.5 added in-app updates that check at startup and daily, download in the background, and finish active print jobs before installing. Version 1.0.6 existed because a reconnect could leave a dead socket behind, and the retired socket could still publish status and schedule its own retries. Neither bug was in the print server. Both were in the agent, and the agent is the part you cannot avoid if the machines are not yours.
Self-host when the printers are yours
Clear cases for building it yourself:
- One site, or a handful you control. No NAT traversal, no agent distribution, no enrollment. Print over IPP and go.
- One operating system you are already good at. Most of the cost above is cross-platform cost.
- You have in-house ops. Somebody already patches those machines and gets paged. Adding a print path to an existing rotation is marginal. Creating a rotation is not.
- Data residency or an air gap. If label content cannot leave your network or your country, a hosted control plane is a compliance project at best. Self-hosting resolves it by construction.
- It interests you. Not a joke. Teams that find printing interesting build print paths that last.
Price in one thing: the print host is an attack surface. The CUPS remote code execution chain disclosed in September 2024 spanned CVE-2024-47176 in cups-browsed, CVE-2024-47175 in libppd, and CVE-2024-47076 in libcupsfilters (a fourth identifier, CVE-2024-47177, was later rejected as a duplicate), with an NVD base score of 9.8 on CVE-2024-47175 and mitigations amounting to disabling cups-browsed and blocking UDP 631. 2025 added CVE-2025-58364 and CVE-2025-58060, an unsafe deserialization of printer attributes and an authentication bypass. This does not make self-hosting wrong. It makes patching those hosts part of the job, which is fine if you were patching them anyway.
Buy when the printers belong to your customers
The signals that push the other way:
- Many customer sites. The problem stops being printing and becomes distribution, enrollment, and support across buildings you have never seen.
- The installer has to carry your name. Customers will not install "PrintAgent" from a company they have not heard of. They will install something branded by software they already bought.
- Your differentiation is elsewhere. If you sell veterinary practice software, nobody picks you for your spooler. Time on certificate renewals is time off the product.
- You cannot administer the machine. No remote management, no consistent OS version, no way to push a patch. The agent has to update and re-register itself, unattended, correctly.
- You need per-customer billing attribution. Metering physical output per tenant, idempotently, without retries double-counting, is its own small system.
A decision table you can score
Give yourself a point per row and see which column wins.
| Signal | Self-host | Buy |
|---|---|---|
| Number of physical sites | 1 to 5 | dozens or more, and growing |
| Who administers the machines | you do | your customer does |
| Operating systems in scope | one | macOS and Windows, mixed versions |
| Existing on-call rotation | yes | no, or you would be creating one |
| Data residency constraints | strict | normal SaaS posture |
| Does the agent need your branding | no | yes |
| Tenant billing on print volume | no | yes |
| Engineers you can spend on this for a quarter | 1 or more | fewer than 1 |
A split result is a real result, and there is a middle path: keep your current print service and add a second for the customer sites that need an agent. We wrote that pattern up in running RocketPrint alongside your current print service, and it works the same way when the incumbent is your own CUPS box.
The two recurring costs nobody budgets: updates and reconciliation
Everything above is build cost. These two are forever.
Updates. An agent on an operational machine cannot behave like a consumer app. It must not install while a label is in flight, it must re-register itself without a human clicking anything, and when it cannot update it must keep working rather than nag. You will get this wrong once, during a shift.
Reconciliation. This separates a print path that works from one people trust. Printing gets no acknowledgment from the physical world. A print command can succeed through the operating system while the ribbon is out. A process can die between issuing the command and recording that it did. So you need a state meaning "we do not know," a policy for it that is not a blind retry, and a list endpoint good enough to answer "what happened to this order" a week later. Build that state on day one. Adding it after you have shipped a two-state success/failure model is painful. More on the shape of it in what print job statuses actually mean, and on the machine that was off for hours in recovering a warehouse printer queue.
What we do, and where we are the wrong answer
RocketPrint is a remote printing API and desktop Station for software platforms: your backend POSTs a print job, and a small app beside the printer prints it, with no inbound networking, no drivers for raw label formats, and a durable job record. A platform account provisions isolated customer workspaces with their own API keys, stations, printers, and jobs, billed on completed jobs and active workspaces. Plans start at $60 per month for 20 active customer workspaces and 100,000 completed jobs, and go to $1,500 per month for 750 and 2,000,000. Paid plans include one branded Station edition.
Where we are the wrong answer, plainly:
- Linux. There is no Station for Linux you can install yourself today. If your print hosts are Linux, self-host or use something else.
- Webhooks. Not shipped. You poll, or you use the Node client's
waitForhelper. If your architecture depends on push, that is a real gap. - Air gaps and private deployment. We do not offer one. If label content cannot reach a hosted service, we are not a candidate.
- A single site you already administer. We would be a subscription replacing a config file.
- Neighbors in this category. We keep a comparison page for PrintNode that tries to be accurate rather than flattering, and if you are evaluating you should read it next to their own documentation rather than instead of it. Printercow takes a different shape again, a Raspberry Pi on the printer's USB port exposing an HTTP endpoint, which for a single printer is less machinery than either of us.
If you are still deciding, the useful next step is not a trial. It is checking whether your plan answers the reconciliation questions above, whichever way you build. The evaluation checklist has the vendor-facing version, the Station docs describe what the agent does on the machine, and the reliability page lists the failures we cannot see.
END / should-you-self-host-your-print-server
More field notes →