Web Development with Clojure

Request handling, routing, middleware, data validation, and service structure for HTTP applications built with Clojure.

This chapter explains how idiomatic Clojure shows up in real web systems: request handling, routing, middleware, API boundaries, authentication, browser integration, state, async work, deployment, and performance. The point is not to memorize a framework stack. It is to learn how Clojure’s data-oriented style changes the shape of a service.

The most reliable Clojure web applications tend to share a few traits:

  • handlers stay thin and explicit
  • middleware order is deliberate instead of magical
  • state is classified before it is stored
  • business rules stay testable outside the HTTP layer
  • async and concurrency tools are chosen for real bottlenecks, not fashion
  • deployment and observability are treated as part of the design, not afterthoughts

Use this section when you want to answer questions such as:

  • which server and routing model fits the workload?
  • what belongs in middleware versus handlers or services?
  • how should sessions, caches, browser state, and durable business state stay separate?
  • when does async web handling really help?
  • how should a Clojure service be packaged, rolled out, and observed?

Two reading paths usually work well.

If you are building or reviewing an HTTP API:

  • start with web framework roles and the Ring request-response pipeline
  • move into routing, middleware, API design, authentication, and error handling
  • then read state, async, deployment, and performance

If you are designing a fuller browser-backed system:

  • start with the Ring pipeline and state management
  • then read front-end integration, APIs, authentication, testing, and real-time communication
  • finish with deployment and performance

The chapter is intentionally practical. It does not assume that every team needs the same libraries or hosting model. Instead, it treats web development as a set of boundaries to design well:

  • request boundary
  • trust boundary
  • state boundary
  • browser-server boundary
  • deployment boundary
  • operational boundary

Once those boundaries are clear, the choice of library becomes easier to reason about.

In this section

  • Overview of Web Frameworks in Clojure
    Learn how Ring, Reitit, Compojure, Luminus, and Pedestal fit together so you can choose a Clojure web stack by role and constraints instead of by brand names alone.
  • Building APIs with Ring and Compojure
    Learn how to build straightforward HTTP APIs on Ring and Compojure, keep route handlers thin, and separate routing concerns from validation, domain logic, and persistence.
  • Asynchronous Web Applications with Async Servlet Support
    Learn when asynchronous request handling actually helps in Clojure web systems, how servlet async support differs from event-loop servers, and where async design goes wrong.
  • RESTful Services Design Patterns
    Learn practical RESTful service design in Clojure, including resource modeling, idempotency, pagination, error shaping, and how to keep HTTP semantics aligned with domain behavior.
  • Authentication and Authorization with Friend and Buddy
    Learn how authentication and authorization fit into Ring applications, when Friend is mainly historical context, and why modular Buddy-style middleware remains a practical model for modern Clojure web apps.
  • Managing State in Web Applications
    Learn how to separate request state, identity state, cache state, client state, and durable business state in Clojure web systems without turning services into hidden mutable tangles.
  • WebSockets and Real-Time Communication with Sente
    Learn how Sente models real-time communication in Clojure web apps, including event-based message handling, WebSocket and fallback transport choices, and where real-time channels are stronger or weaker than simpler alternatives.
  • Middleware Patterns in Clojure Web Development
    Learn how Ring middleware should be used in Clojure web applications, including ordering, request enrichment, response shaping, and the line between cross-cutting concerns and business logic.
  • Testing Web Applications
    Learn how to test Clojure web applications at the handler, middleware, routing, and integration levels, and how to keep web tests fast enough for development without losing honest coverage of HTTP behavior.
  • Deployment Strategies for Web Services
    Learn how modern Clojure web services are packaged, configured, containerized, rolled out, and monitored so deployment stays boring instead of surprising.
  • Performance Optimization in Web Applications
    Learn how to measure and improve Clojure web performance by attacking the real bottlenecks: database latency, blocking calls, oversized payloads, poor caching, and avoidable work.
  • Front-End Integration with ClojureScript
    Learn how ClojureScript fits into a modern Clojure web stack, where shared code really helps, and how to structure browser-server boundaries without turning the app into one blurred codebase.
  • Server-Side Rendering and Templating with Selmer
    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.
  • Error Handling and Logging in Web Contexts
    Learn how to handle web errors and logging in Clojure applications, including exception mapping, structured logs, request correlation, and avoiding information leakage in HTTP responses.
  • The Ring Request-Response Pipeline
    Learn how Ring models HTTP as request and response maps, how middleware wraps handlers, and how a request moves inward while the response moves back out through the pipeline.
  • Microservice Architecture with Clojure
    Learn when microservices are actually worth their cost in Clojure systems, how to draw better service boundaries, and how to keep communication and data ownership explicit.
Revised on Thursday, April 23, 2026