Learn when Selmer is a good fit for server-rendered Clojure web apps, how to keep templates presentation-focused, and how to avoid pushing too much application logic into the view layer.
Selmer: A Clojure templating library for rendering HTML from plain data using a Django-inspired template syntax.
Server-side rendering remains useful when the application wants fast first paint, straightforward HTML delivery, or a simpler operational model than a heavy client-side application. Selmer fits well when you want to keep the web boundary data-driven while still producing normal server-rendered pages.
Templates should describe presentation, not become the place where the application thinks.
That means:
If business rules or data fetching creep into the view layer, the page becomes harder to test and harder to evolve.
This is one reason server-rendered applications often age well when they stay disciplined. The handler or service prepares the facts, and the template describes presentation. Once that split blurs, SSR starts to feel heavier than it needs to be.
One practical discipline is to prepare a view model in Clojure before the template runs:
That keeps the template from becoming a second programming language for business logic.
It also makes HTML review easier. When the template receives prepared values, most display changes remain visible as presentation changes instead of hidden application behavior changes.
1(require '[selmer.parser :as selmer])
2
3(selmer/render
4 "<h1>{{ title }}</h1>{% if admin %}<p>admin view</p>{% endif %}"
5 {:title "Dashboard"
6 :admin true})
The template stays focused on presentation, while the application code decides what values the template receives.
Selmer is a strong fit for:
It is less attractive when the page is mostly a client-side application that immediately takes over and manages complex browser-side state.
That boundary matters because some teams use SSR mainly as a delivery shell for a heavy client app. That can be a valid architecture, but it should be recognized as such. Otherwise the project ends up paying for both rich SSR complexity and rich client complexity without clear ownership.
Layouts, partials, and fragments are useful, but they should reflect genuine presentation reuse:
If partials start hiding domain decisions, the abstraction has moved too far down into application logic.
Templating is part of the web security surface. The safe default is to treat template output as user-facing HTML that must not casually render untrusted content. The more a system mixes trusted markup and untrusted user input, the more carefully the rendering boundary must be designed.
This is another reason to keep the template layer presentation-focused rather than logic-heavy.
Forms and embedded user input deserve the same discipline. Escaping rules, CSRF boundaries, and error-display logic are all easier to reason about when the template is not also inventing domain policy.
Templating pays off when shared structure stays reusable:
Reuse is strongest when the shared pieces represent real presentation repetition, not when templates become a second programming language.
One useful question is whether the page is:
The answer changes how much complexity belongs in the templating layer versus API or browser code.
Partials help when they encode repeated presentation structure:
They hurt when they become hidden containers for business rules. If several templates must know subtle domain conditions to use a partial correctly, the view abstraction is probably too clever.
Selmer-based pages go wrong when:
The template engine should make HTML clearer, not move the application core into string generation.
If the page is really a client-heavy stateful application, forcing too much through the server-rendered template layer can produce duplication instead of clarity.
Use Selmer when the app benefits from server-rendered HTML and data-first view models. Pass templates fully prepared data. Keep display conditions modest. When a template starts to feel like business code, move the logic back into Clojure.