Liking cljdoc? Tell your friends :D

Why Boundary?

The problem with Clojure web development

Clojure is an excellent language for building reliable systems, but the ecosystem lacks opinionated, batteries-included frameworks. Most projects start from scratch, wiring together Ring, Reitit, next.jdbc, Malli, Integrant, and a dozen other libraries. Each project reinvents the same patterns — authentication, pagination, validation, admin UIs — differently.

What Boundary solves

Boundary packages the best-practice assembly of these libraries into a coherent whole, with one non-negotiable rule: the Functional Core / Imperative Shell pattern is enforced at every layer.

For developers: 19 composable libraries

Use just boundary-core for validation utilities in an existing app, or compose the full stack with JWT + MFA auth, auto-generated CRUD UIs, background jobs, multi-tenancy, real-time WebSockets, and more.

Every library follows the same FC/IS structure, making any Boundary codebase instantly familiar.

Ship faster with the scaffolder

bb scaffold ai "product module with name, price, stock"

The scaffolder generates production-ready modules (entity + routes + tests) in seconds. The admin UI auto-generates CRUD interfaces from your schema — no manual forms. Built-in observability, RFC 5988 pagination, and declarative interceptors mean you write business logic, not plumbing.

Zero lock-in

Each library is a standard deps.edn dependency. Swap what doesn’t fit. If you don’t need multi-tenancy, don’t include boundary-tenant. If you prefer a different caching backend, implement the ICache protocol.

The FC/IS guarantee

The most important property Boundary enforces is the separation between pure and impure code:

libs/{library}/src/boundary/{library}/
├── core/       ← Pure functions only. No I/O, no logging, no exceptions.
├── shell/      ← All side effects: persistence, HTTP, services.
├── ports.clj   ← Protocol definitions (interfaces).
└── schema.clj  ← Malli validation schemas.

This keeps business logic:

  • Fast to test — no mocks needed for core functions

  • Easy to reason about — given the same input, always the same output

  • Safe to refactor — the type system and tests catch regressions immediately

Compared to alternatives

PropertyBoundaryPedestalLuminus

Enforces FC/IS

Yes

No

No

Scaffolder

Yes (AI-assisted)

No

Partial

Admin UI

Auto-generated

No

No

Library granularity

20 independent libs

Monolithic

Template-based

Multi-tenancy

Built-in

No

No

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close