Modern server rendered apps


Basecamp recently launched their new e-mail service and made a big splash with their tech stack. They use a monolithic Rails app with minimal Javascript on the frontend and still deliver great user experience.

Granted, they use basically the same stack for Basecamp so they know what they’re doing, but also big sites like Github employ similar methods (server-rendered partials).

Although this is quite uncommon, it still goes against the web development trends of last years. Let’s look into the whats and whys.

Why not use a frontend framework? πŸ”—

Frontend frameworks are very popular. They allow frontend developers to create interactive user experiences while not caring much about the backend.

But, building an full-blown SPA usually pushes a lot of work to the client - the users browser and we end up duplicating business logic on both the backend and frontend.

It is possible to sprinkle some Javascript components here and there to enrich some of the interactions in a classical server-rendered app, but soon enough the frontend framework ends up eating it all. And we’re back to building a SPA.

If you want to build your frontend in React, Vue.js or another hot JS framework but would like to keep the benefits mature backend frameworks give you, there is another way. Check out Inertia.js, a framework-agnostic library that let’s you swap the view layer of your backend framework with a frontend framework of your choice while keeping the benefits and reducing downsides of both.

With that said, let’s see how we can build modern apps without a full frontend framework.

The stack πŸ”—

Let’s go over the pieces of a modern server-rendered app stack.

Server-side frameworks πŸ”—

The most famous example is Phoenix Liveview, which was announced in 2018. Phoenix is a web framework for Elixir, a functional language built on top of Erlang. The premise is simple:

LiveView provides rich, real-time user experiences with server-rendered HTML.

And it is astonishing.

Livewiew lets you create dynamic user interfaces on the back-end without writing any JavaScript. On first request the server renders the page and returns it to the client. Then the client establishes a secure connection back to the server. On subsequent changes the server rerenders the relevant parts of the page and pushes them back to the client. The client then merges the changes into the page efficiently.


Even though Elixir isn’t the most widely used, Liveview inspired people to start implementing similar methods in other languages.

Laravel Livewire became very popular in the Laravel community over the last year or so. It works in a similar way, only over AJAX because PHP is stateless.

There’s StimulusReflex for Rails, Sockpuppet for Django and many others for different languages/frameworks.

Even Common Lisp has a similar framework called Weblocks. That dates back to ~2011.

Wait… What?

Yeah, not all new ideas are completely new. Although the original Weblocks seems to be abandoned, there’s been a newer active fork since. Time passes differently in the CL world…

Let’s go over the benefits of using such framework.

  • Single source of truth

    The front-end state is managed on the back-end, where you likely do other things like interacting with a database or authenticate users.

  • Reduced complexity

    No need to build a separate frontend in a (likely) different language with duplicate business logic. You get to stay in your back-end codebase.

  • Low network usage

    Depends on the specific implementation, but generally only messages and HTML/data diffs are transmitted over the network, which at worst matches a data usage of an SPA, at best you even save.

There are cases a framework like this would not be a good choice, such as real-time animations and games or toggling a modal, but for the 90% of web applications it should work great.

Sounds like a win-win!

Just keep in mind, while the libraries are production ready, they are still quite new.

Minimalist Javascript frameworks πŸ”—

Stimulus.js (by Basecamp) and Alpine.js are examples of small JavaScript frameworks designed to enrich existing HTML without taking over the whole front-end.

Here’s an examle of a dropdown in Alpine.js:

<div x-data="{ open: false }">
    <button @click="open = true">Open Dropdown</button>

        @click.away="open = false"
        Dropdown Body

What makes Alpine great is that the directives are written directly in HTML, so you don’t need any new files or build steps. And the syntax is Vue.js-like which makes it very readable and easy to use. You can find more examples and installation instructions in the Github repo.

Turbolinks (also by Basecamp) is an interesting small library that gives a server-rendered app the feel of an SPA. Behind the scenes Turbolinks replace links in your app with AJAX request and then replace the page’s <body> with the newly fetched HTML from the server.

This is a great and simple approach, but it has a few pitfalls.

  • You have to tell Turbolinks not to replace outbound links, otherwise stuff will break magnificently.
  • The page swap mechanism only swaps the body - if a specific page requires any additional scripts/styles/head tags etc. you need to work that out.

That said, using Turbolinks is an easy way to give a boring old server rendered app a modern SPA-like feel.

πŸš€ Put it all together! πŸ”—

  1. Build your server-rendered app as usual.
  2. Replace parts where you would use a frontend framework with a solution like Liveview (form submissions, tables etc.).
  3. Sprinkle in some JavaScript with Alpine or Stimulus (for dropdowns, modals and small things like that).
  4. Top it up with Turbolinks for SPA-like page reloads.

That’s it!

You now have an app that feels fast and modern without writing any (or almost any) frontend JavaScript code!