PaaS Design Principles
There are two ways to build a PaaS. I'll call them top-down or bottoms-up1.
Top-down PaaS are framework and language-specific – think NextJS on Vercel (or SpringBoot for the old-timers). They are highly opinionated – choosing NextJS means choosing React, single page application, and Node.js.
Bottom-up PaaS look a lot more like IaaS. For example, there are PaaS built on Kubernetes, like Kubeflow, Knative, or OpenShift. These layers hope to be building blocks of bundled and abstracted IaaS.
It's almost always a mistake to design a PaaS somewhere in-between. Specifically, the cardinal rule of bottoms-up PaaS is often broken.
Never build language-specific features
Language-specific features mark the slow demise of many PaaS.
Maintenance nightmare. M language runtimes multiplied by N supported versions. It's difficult to ship even a single (and highly opinionated) runtime.
Bag of Abstractions. Per-language abstractions often share little in common. For example, if your PaaS supports Node.js and Go applications, the runtimes likely share little in common. Instead of being an abstraction, these PaaS create a bag of abstractions that are unrelated to each other: different runtimes, different middleware, different deployment, and different observability.
Optimization is fragile. Top-down and bottom-up PaaS focus their optimization – either on a particular use-case or IaaS (even the successful top-down PaaS focus on select pieces of IaaS, e.g., Vercel = CDN + Functions).
An excellent (somewhat) recent example of technology following the rule is Language Server Protocols. While the goal of LSPs might have been IDE tooling portability, it also greatly simplified the process of building language-agnostic developer tooling.2
1Here I'm talking about open-source or commercial PaaS products. An internal PaaS developed by a platform team is likely to resemble a top-down PaaS simply because the technology is inherently opinionated – framework and language-specific.
2Language servers are, of course, still language-specific. However, the Language Server Protocol itself is language-agnostic.