Skip to content
All posts

Frontend

Server-Driven UI Is Not a Downgrade

Md Shamim Hossain October 8, 2026 4 min read 3,105 views Updated Oct 26, 2026

The reflex to reach for a SPA has a cost most teams never price in: a duplicated domain model and a second place for authorisation to be wrong.

More ways to share

Link copied to clipboard

Somewhere in the last decade "modern frontend" became a synonym for "React", and the default answer to "we need interactivity" became "we need a SPA." I want to make the case that for a large class of applications this trades a real problem for two invented ones.

What the SPA actually buys you

Be precise about it, because the benefits are real and only sometimes present:

  • Rich interaction at 60fps without a round trip. Genuinely necessary for editors, canvases, and drag-heavy tools.
  • Offline capability with a local-first data model.
  • Decoupled release cadence between a client team and an API team.
  • Reusable client logic across web and mobile.

If you have none of these, you are paying the cost without collecting the benefit.

What it costs

A duplicated domain model

Your backend has validation rules. Your form now needs the same rules so it can fail fast. Now there are two implementations, and they diverge.

// app/Livewire/.../PostEditor.php — one source of truth
$validated = $this->validate([
    'title' => ['required', 'string', 'max:255'],
    'body' => ['required', 'string'],
]);

With a SPA, that array exists twice: once here and once in a TypeScript schema file. The client copy is the one users see; the server copy is the one that actually protects the system. Keeping them aligned is ongoing work that produces no user-visible feature.

A second authorisation surface

Every endpoint the SPA calls is a public endpoint, even the ones only your dashboard uses.

// With Livewire: authorisation runs inside the component method.
Gate::authorize('update', $post);

With a SPA, that same check must also exist as middleware on the API route, and the component must not assume the check happened. Two places, one of which will eventually be forgotten on a new endpoint.

A loading state for everything

Server-rendered pages arrive complete. SPA screens arrive empty and then fill in, so every view needs a skeleton, an error state, and an empty state — three designs per screen instead of one.

What server-driven UI actually looks like

The point is not "no JavaScript." It is that the authoritative state stays on the server and the client sends small intents.

<?php

use App\Models\Post;
use Livewire\Component;

new class extends Component {
public string $search = '';
public ?string $category = null;

#[Url]
public int $page = 1;

public function updatedSearch(): void
{
$this->page = 1;
}

public function render()
{
return view('livewire.blog-index', [
'posts' => Post::query()
->published()
->with(['category', 'tags'])
->when($this->search, fn ($q) => $q->search($this->search))
->when($this->category, fn ($q) => $q->inCategory($this->category))
->recent()
->paginate(9),
]);
}
};
```

The search term, the filter, and the page live in PHP. Validation and authorisation live in PHP. There is exactly one implementation of every rule, and it is the one that runs.

The client receives a diff and patches the DOM. On a warm connection that is 40–80ms — fast enough that the interaction reads as instant, and slow enough that you notice when you have built something that should have been a plain link.

Where I still reach for a SPA

Saying "never" would be its own kind of reflex. I reach for a client-side framework when:

  • The interaction is continuous rather than discrete — a canvas, a timeline editor, a drag-to-reorder board with hundreds of items.
  • The app must work offline.
  • There is a genuinely separate client team with a genuinely separate release cadence, and the coordination cost of a monolith exceeds the duplication cost of an API.

Notice that all three are about the shape of the work, not about how modern it feels.

The question to ask

Instead of "should we use React," ask: where does the authoritative state live, and how many places enforce the rules?

If the answer is "in the database, enforced in one place," then a server-rendered interface with targeted reactivity is not a downgrade. It is the short path to a system with fewer ways to be wrong.

Keep reading

Discussion

3 comments

Sign in to join the discussion. Comments are published under your name.

Markdown-style emphasis and `code` are supported. 0 / 2000
Held for moderation
  1. H

    Hannah Lin

    We hit exactly this bug last quarter. Two hours of production debugging for a one-line ordering clause.
  2. A

    Anika Sorensen

    Small nit: the third code block is missing its language tag, so the syntax highlighting falls back to plain text.
    1. T

      Tomas Delgado

      reply
      Good catch — fixed. The renderer reads the fence info string, so a bare fence loses highlighting entirely.
Enter your credentials to continue to your workspace.
Email address
Remember me
Don't have an account? Sign up
Enter your details below to create your account
Name
Email address
Password
Confirm password
Already have an account? Log in
Enter your email and we will send you a reset link
Email address
Or, return to log in