If you’re starting a startup, which backend framework should you use? Or, if you’re an engineer looking to enhance your backend skills by learning a new framework, which one should you learn?
Backend frameworks come in different levels of abstraction, from highest to lowest, as this infographic shows:
Low-Code
Low-code frameworks are the highest level of abstraction. You get to the outcome the fastest. The barrier to entry is the lowest, so a semi-technical sole founder like a PM, designer or marketer can build a minimal product by himself. Or even a series of such prototypes to see which one has potential before focusing on that. Or a person who wants to quit his job to start a startup can do build a product on the side, validate it, and only then quit his job. Or a person in a company who has an idea can build a proof of concept to show to other stakeholders. Maybe validate it with users, and thus convince other stakeholders to get it implemented it properly using whatever stack the company uses, like Django. Or the marketing team can build a side project in a week whose primary purpose is to have more users hear of and use the company’s primary product. My financial advisor used a low-code tool to build a retirement savings calculator, and he’s not a tech startup.
Low-code frameworks have a ton of uses. This is a specific example of a general principle that when the barrier to doing something reduces, tons of use cases open up [1].
Unfortunately, low-code tools are not portable. You create a tool using a certain service, and it runs on that service. One tool we considered using even charges per user, not per developer, resulting in an annual bill of thousands of dollars for our startup of 20-something people, which obviously make not even waste time evaluating that tool.
Whether low-code tools in general, or the tool of your choice in particular, support a polished user experience for a user-facing, as opposed to just an internal, app needs to be figured out.
Backend as a Service (Firebase)
If you can’t or don’t want to use a low-code tool, the next lower level of abstraction is a backend as a service (BaaS). The only mainstream option there is Firebase. You build your mobile and web apps, and skip building your backend. Firebase provides one for you. It also provides the client-side model objects, data fetching, caching, offline, sync and conflict resolution, which is a huge amount of work. Firebase used to support only mobile apps, but it now supports web apps, too.
Unfortunately, Firebase locks you into Google Cloud. When I was running my startup Futurecam, Google threatened to terminate my account because their systems could not charge me 1 paisa. Their support was useless. If you built your product on Firebase, you can’t even move to AWS if Google threatens you.
PostGraphile
PostGraphile is a project that autogenerates a GraphQL backend for you given a Postgres database. So you define your database and your frontend apps, skipping the backend layer [2]. Instead of mapping columns in your database to fields in JSON, which is busywork [3], directly expose the database. Instead of authenticating users in your backend code, you can use the database’s row-level security, where every user’s data is tagged with their user ID, and only that user can access that data. Databases are powerful, and the typical app uses only 5% of their power, re-implementing the rest, which doesn’t make sense.
If you want a REST API rather than a GraphQL one, there’s an alternative to PostGraphile, called PostgREST.
Since both PostGraphile and the underlying Postgres are open-source projects, supported on multiple clouds, there’s no risk of lock-in. So if you’re considering picking between PostGraphile and (say) Firebase for your project, take that into account.
If you’re an engineer thinking about which technology to learn next, learning a technology that’s portable has more value than one that’s locked in, everything else being equal, because the chance that you can use it in your next job is higher. For example, if you learn Firebase, but the next company you work with has already built their backend on AWS, your investment isn’t as useful.
FaaS
FaaS is a promising architecture for backends, solving a bunch of problems that plague backends built with traditional frameworks, while being easier to get started with, and scaling to more complex codebases. These are often tradeoffs: a tool can be easier to get started with, but not scalable. FaaS gives you many of these benefits at once.
Unfortunately, Functions have high cold start latency, making them unsuitable for user-facing traffic [4].
FaaS is not portable, since even the function signatures change between AWS and Google, not to mention dependencies on other services like identity, event queues, object storage, etc, which are more than in a traditional architecture.
Traditional Backend on a Serverless Platform
You can build a backend using a traditional framework like Django or Rails and run it on a serverless platform like Google App Engine. The platform takes care of scaling, managing and updating the underlying OS, some amount of security, etc. You’re charged for the requests handled, rather than sizing your infrastructure to the peak load and paying for that 24x7. In other words, you’re paying for business value and not for infrastructure.
At the same time, you get the benefits of traditional frameworks: Django and Rails are tried and test frameworks that can do everything you need. Their limitations, and workarounds for these, are also well-known. There are tons of engineers who know these, from the point of view of hiring, or consulting an engineer when you have trouble. Traditional backend frameworks like Rails and Django are boring, in the best possible way. They’re the lowest risk, in the sense of having to rebuild your product because Django didn’t work [5].
Because a framework like Django is portable, you can choose between clouds. Or run it on-premise. Even within a single cloud, say Google Cloud, if you want more control than App Engine, Google offers a slightly lower level, but still serverless, platform called Cloud Run. If serverless is too high-level, you can later drop to using a server-ful framework like Kubernetes. Or even raw VMs. You can see how Google Cloud can run Django using four different hosting options at different levels of abstraction. This is a benefit to using a traditional framework like Django or Rails — you keep your options open. This is relevant since you don’t know today what you’ll need in the future.
One way of looking at the decision to use a traditional backend framework on serverless is that you get the best of both worlds — the benefits of a traditional backend, and that of serverless.
Traditional Backend on a Server-ful Platform
This is the traditional approach: use Django or Rails or whatever other framework, and host it on a server-ful platform like Kubernetes or even raw VMs. You might end up at this level if your company scales to a billion dollars, at least for some services, but you don’t want to start here unless there’s something specific about your workload that requires it.
Portability
Let’s now look at the above spectrum of options through the lens of portability. Say you want to pick a framework that doesn’t lock you in to a particular cloud, or a particular company’s services. What are your options?
The highest level of abstraction is PostGraphile, where you don’t have to build a backend. One level lower is a traditional framework like Django, ideally running on a serverless platform like App Engine, or if not, running on a server-ful platform.
From a learning point of view, the above are good. If you’re going to learn a framework, there’s value in learning one that’s portable, so that your investment has a greater return.
But if you’re picking a framework to implement your backend in, don’t overweight portability. Balance it against the risk of your startup going bust because you didn’t use the most efficient tool for the job.
If you’re interested in the frontend, read Levels of Abstraction For Frontend Frameworks.
[1] For example, when the Internet made it possible for everyone to broadcast their thoughts to the world, without having to get a job at a magazine, blogs became possible.
[2] If you want a commercial service, consider Hasura.
[3] Unless you do, such as if you’re offering a public API, or if your product is at a big enough scale. Add layers of abstraction and indirection when you need them, not automatically.
[4] AWS Lambda offers provisioned concurrency, where you can say that you want (say) 10 instances of your Function always available. As long as your traffic is less than 10 simultaneous invocations, users don’t see cold start latency. If you have more, users will see cold start. Unfortunately, this is only a partial solution — if you set this to a high value, your costs will increase, and much of the capacity you’ve bought will be idle. If you set it to a low value, you’re not solving the problem.
I’d like an option to increase the idle timeout for a Function to 1 hour before it’s shut down. This virtually eliminates cold starts, while still letting me save money by taking advantage of the diurnal cycle, rather than sizing resources to the peak.
Google Cloud Functions are worse than AWS, since it doesn’t even offer provisioned concurrency.
[5] But that’s not the only dimension of risk. The other, no less important one, is that you execute slowly, losing to nimbler competitors. This might happen if you invest too much time building infrastructure rather than creating business value. This, in turn, happens if you choose too low a level of abstraction from the list above.
I researched a bit about this recently and came up with same conclusions.
Am going with Hasura + Postgres as backend for the next Product.
Thinking of Going with Flutter for front-end (Mobile) but a similar analysis on Front-end would be awesome.