Printster.in has been printing documents, theses and books for customers across India since 2014. The idea hasn't changed: upload a PDF, choose paper, sides and binding, see the price instantly, and get it delivered.

The code behind it has changed. For most of its life Printster ran on a single Laravel/PHP application. This post covers what we moved to and why.

Why move off the monolith

One app was doing everything: the customer-facing pages, file upload and cart, the price calculation, and the admin our team uses to run orders. Every change touched the whole thing, and the public pages that matter for search were tied to the same release cycle as the order system.

What we moved to

  • API: Bun + Hono. A small, fast HTTP layer that the rest of the system talks to.
  • Frontends: React / Next.js, split into separate apps: a storefront for catalogue and SEO pages, a customer app for upload, cart and ordering, a designer app where customers design products before sending them to the cart, and an admin for categories and products.
  • Monorepo: Turborepo, with shared packages so every app uses the same types and business logic.
  • Data: MySQL/MariaDB.
  • Hosting: Hetzner servers deployed with Coolify, behind Cloudflare.

What the split gave us

  1. One source of truth for pricing. Per-page prices depend on paper size, GSM, single or double-sided, and quantity (with automatic bulk breaks). Keeping that logic in one shared package means the storefront, the customer app and the admin can't disagree about a price.
  2. Server-rendered pages for search. Next.js lets us render the rate card, city pages and printing guides on the server, with structured data, so search engines and AI assistants can read them. Our rate card is public: printster.in/print/pricing
  3. Independent deploys. A copy change on the storefront no longer ships alongside a change to order handling.

If you're doing the same

  • Move the pricing and business rules into shared code first; the UI is the easy part.
  • Keep the database stable while you swap the layers in front of it.
  • Treat SEO pages as their own app with their own release cycle.

If you need something printed in India, upload it at printster.in. And if you've moved a legacy PHP app onto a TypeScript stack, we'd like to hear how it went in the comments.