Build platform, not product: how shared primitives let one person launch several SaaS products
My platform started as a Markdown editor. Over time, a web reader, APIs, an internal panel, licensing, auth and the clear idea of a publishing service appeared around it. The platform did not come from a blank page. It was hidden inside the product.
NoteThe signal was not "I want to launch many SaaS products". It was this: every new product reused the same renderer, the same identity layer, the same quotas and the same delivery flow.
From product to platform
The difference between product and platform is not the size of the diagram. It is whether the shared pieces have their own contracts and can support new products without being copied.
Signs that you already have a platform
Repeated code
The same renderer appears in the editor, the web and dashboards. It is not a utility. It is core.
Shared services
Identity, licensing, billing, quotas and deployment keep showing up in every product.
Low marginal cost
The next product does not start from zero. It composes existing primitives and adds a thin layer.
Inventory of primitives
A useful platform is small. If everything is a primitive, nothing is.
| Primitive | Contract | Products that use it |
|---|---|---|
| Render core | Enriched Markdown to safe decorated HTML | Editor, web, dashboards, publishing, portal |
| Identity service | Identity, sessions, MFA and scopes | Any product with login |
| Licensing service | Plans, quotas, entitlements and billing | Editor, publishing, portal, API |
| Server-side render service | Server-side rendering and exports | Publishing, export API, portal |
| Publishing service | Deploy, themes, domains and audit | Publishing, portal |
| Edge / object storage layer | Assets and static sites | Publishing, portal |
ImportantA primitive knows its domain. A product knows the primitive. If a primitive starts knowing products, it becomes a disguised monolith.
Products on the same base
| Product | What it sells | What it reuses | What it adds |
|---|---|---|---|
| Editor | Local-first authoring | Render, identity, license | Desktop UI, Git, local export |
| Publishing | Publish Markdown repos | Render, identity, license, deploy | Themes, domains, sites |
| Customer portal | Private delivery to customers | Render, identity, license, deploy | Customer-project model |
| Exports API | PDF/HTML/Word through an API | Render, identity, license | Public endpoints and quotas |
The platform lets products share infrastructure without forcing them to share the same user experience.
The economics of reuse
The value appears when marginal cost drops:
$$
new_product_cost = specific_layer + integration(primitives)
$$
If the specific layer is small, one person can sustain more than one product. If every idea needs identity, billing, rendering and deployment from scratch, there is no platform. There is only a list of projects.
Boundaries that prevent a monolith
| Boundary | Practical rule |
|---|---|
| Identity | Issues tokens with scopes; does not decide product screens |
| Licensing | Models plans and quotas; does not contain commercial copy |
| Render | Renders Markdown; does not know if it is in editor, publish or portal |
| Deploy | Publishes bundles; does not decide navigation or content |
Checklist before accepting a new primitive
- It has a clear input and output contract.
- At least two real products need it, or one critical product and another waiting.
- It does not contain copy, layout or product-specific cases.
- It can be tested without starting the whole platform.
- It has an owner, README and version.
- It replaces duplication that already hurts, not a future hypothesis.
How I plan new products
The first question is no longer "what do we need to build?". It is:
TipWhich existing primitives does this product reuse, and which new primitive does it force into existence?
| Answer | Decision |
|---|---|
| Reuses almost everything and adds a thin layer | Good candidate |
| Reuses part of the system but creates a valuable primitive | Can enter the roadmap |
| Requires a different platform | Does not belong here |
| Pollutes existing primitives with strange cases | Reject or isolate it |
The organizational part
Even as one person, the architecture needs clear compartments:
- One repo or package per primitive.
- Tests where the contract lives.
- Products as consumers, not owners of the core.
- Central documentation for decisions and boundaries.
- Small migrations, with visual parity when UI is involved.
Discipline matters more than headcount. If I mix domains in my head, the code will mix them too.
The rule I keep
Platforms are not built from scratch. They are recognized when the same primitives already support several products and you start naming, versioning and protecting their boundaries.
This article is part of my platform notes. If you are interested in this work, follow the blog or contact me.