HN Debrief

My thoughts after using Clojure for about a month

  • Programming
  • Developer Tools
  • AI
  • Infrastructure
  • Open Source

The post is a newcomer’s field report after about a month of using Clojure to build real things, including the author’s own website. They came away impressed by how much the language pushes you toward data transformation instead of object plumbing. The big wins were immutable collections, the seq abstraction that lets one set of functions work across many collection types, and a standard library that feels smaller and more coherent than Common Lisp. The frictions were also exactly the expected ones: dynamic typing, unfamiliar syntax around mixed delimiters, and the sense that Clojure is easiest to love once you also buy into its editor and tooling habits.

If you are evaluating Clojure, focus less on whether the Lisp syntax clicks immediately and more on whether you want immutable-by-default programming, REPL-driven development, and structural editing. If you last dismissed it because it rode on the JVM, recheck that assumption against today’s virtual threads and the growing cross-runtime ecosystem around Babashka, ClojureScript, and jank.

Discussion mood

Mostly positive and a little nostalgic. People liked seeing a newcomer rediscover why Clojure feels fresh, and the praise centered on immutable data, REPL-driven development, and structural editing. The only sustained friction came from dynamic typing concerns and from older assumptions about the JVM, which many commenters said are outdated now that Java has virtual threads.

Key insights

  1. 01

    Cross-runtime portability is real when tested

    Clojure’s portability is not just a slogan about having many dialects. People building real tools across Clojure, ClojureScript, Babashka, ClojureCLR, Basilisp, and jank said the reusable core is substantial if you keep host-specific IO at the edges and run a test matrix across targets. One commenter even described adding Python support to an existing .cljc codebase in about an hour, with most effort spent fixing platform-specific tests rather than rewriting business logic.

    If you want one codebase across browser, server, CLI, or scripting contexts, keep interop isolated and make cross-runtime tests part of the project from day one. Clojure’s portability pays off only when you treat it as a testing discipline, not a marketing promise.

      Attribution:
    • Jeaye #1 #2
    • djblue #1
    • EnigmaCurry #1
  2. 02

    Structural editing is part of the language experience

    The delimiter complaints stop being the main story once you use structural editing. Paredit, Parinfer, and built-in sexp navigation turn Clojure code into something you move through and reshape as a syntax tree. That changes the editing model enough that several people said going back to plain text editing in other languages feels like a regression, while others noted that without these tools even common Vim habits like deleting a line can leave you in bracket-repair mode.

    Do not judge Clojure from raw text editing. Try it with Paredit or Parinfer before deciding whether the syntax is elegant or unbearable.

      Attribution:
    • pgt #1
    • perrygeo #1
    • Sharlin #1
    • drob518 #1
    • acdw #1
  3. 03

    REPL access changes how LLMs and humans work

    The REPL was framed as more than a convenience for exploratory coding. It gives both developers and coding agents a tight feedback loop where small pieces can be evaluated against live data, libraries, or even a running program before composing them into larger changes. Commenters claimed this makes Clojure unusually effective for tool-assisted development despite one-shot model benchmarks often looking weak on syntax reliability.

    If you use AI coding tools, pair them with executable feedback instead of relying on completions alone. Clojure’s payoff grows when the model can evaluate code incrementally through nREPL or similar tooling.

      Attribution:
    • chamomeal #1
    • jwr #1
    • everforward #1
  4. 04

    Syntax shapes design through what feels easy

    The best rebuttal to “syntax scarcely matters” was not aesthetic. It was that syntax and standard library shape architecture by making some moves cheap and others awkward. Clojure’s literal syntax for maps and vectors, plus uniform collection functions, puts data-oriented design within easy reach in a way Java does not, even on the same runtime. The post author chimed in to say this was exactly the point they were trying to make when comparing Clojure with Common Lisp.

    When evaluating a language, look at what common structures and transformations are one line away. That convenience gradient determines the architecture most teams will actually build.

      Attribution:
    • weavejester #1 #2
    • acdw #1
  5. 05

    The JVM concurrency objection is dated

    Several commenters pushed hard on the claim that Clojure is held back by the JVM for highly concurrent work. They argued that Java 24 era virtual threads now behave much like Go’s goroutines for most practical purposes, including very high thread counts and low memory overhead. That does not erase the tradeoffs between JVM, Go, and BEAM, but it does undercut the old assumption that choosing Clojure means giving up modern lightweight concurrency.

    If your mental model of JVM concurrency is from years ago, update it before rejecting Clojure on scaling grounds. The current question is workload fit and ecosystem tradeoffs, not whether the runtime is fundamentally incapable.

      Attribution:
    • cogman10 #1
    • pdimitar #1
    • foxygen #1
  6. 06

    LLM syntax failures are partly a code shape problem

    People looking at language benchmark results argued that Clojure’s low one-shot success rate may reflect code generation patterns as much as language quality. Deep nesting and back-loaded evaluation order make raw s-expressions harder for models to emit correctly in one pass. Commenters suggested keeping functions shallow and leaning on threading macros like -> and ->> so the written order better matches execution order, which helps both models and humans.

    If you want better results from coding agents in Clojure, constrain style rather than blaming the language wholesale. Shallow functions and thread-first macros can improve correctness without changing the underlying design.

      Attribution:
    • xoxolian #1
    • regularfry #1
    • pjmlp #1

Against the grain

  1. 01

    Dynamic typing remains a real adoption blocker

    For people coming from typed functional languages, the main issue was not Lisp syntax at all but the cost of losing compile-time guarantees. One commenter described confusing runtime failures after passing the wrong nested data into standard library functions. The sharper critique was that REPL habits and tests do not replace machine-checked invariants during refactors, even if defenders correctly pointed out that static types also impose real design constraints.

    If your team depends on the compiler to carry invariants through large refactors, Clojure may feel like a step backward unless you add schemas, specs, or very disciplined testing. Evaluate that workflow cost early instead of assuming the REPL will make it disappear.

      Attribution:
    • perarneng #1
    • IceDane #1
    • weavejester #1
  2. 02

    Hiring risk can outweigh language elegance

    Not everyone bought the idea that a niche language’s quality justifies using it in business. The skeptical view was blunt: a small talent pool creates ongoing replacement risk for any company that needs steady hiring, regardless of whether the language is loved by experts. Replies pushed back that niche ecosystems can attract stronger and better-paid developers, but the operational concern about staffing never really went away.

    If you are choosing Clojure for a company rather than a personal project, plan the recruiting story as seriously as the technical story. Language fit is not enough if backfilling roles will become a chronic bottleneck.

      Attribution:
    • zuzululu #1 #2 #3
  3. 03

    Tree-based editing does not generalize cleanly

    The excitement around syntax-aware editing ran into an older caution from someone who remembered syntax-directed editors in practice. The warning was that tree-first editing sounds obviously superior until you try to make it flexible enough for day-to-day use across richer languages, where it often becomes more annoying than text editing. Lisp gets unusually far here because its syntax is small and regular.

    Treat Clojure’s editing advantages as a special-case win, not proof that all programming should move to AST-first editors. The approach may be excellent for Lisp and still fail to scale to messier language grammars.

      Attribution:
    • mpweiher #1

In plain english

.cljc
A Clojure source file format meant to be shared across multiple Clojure runtimes with conditional platform-specific code.
Babashka
A fast scripting environment for Clojure that starts quickly and is commonly used for command-line tools and automation.
Basilisp
A Clojure-like language and runtime that targets Python.
BEAM
The virtual machine used by Erlang and Elixir, designed for lightweight processes, message passing, and fault tolerance.
ClojureCLR
A Clojure implementation that runs on Microsoft’s .NET Common Language Runtime.
ClojureScript
A version of Clojure that targets JavaScript environments like the browser or Node.js.
interop
Interoperability with the host platform, meaning calling libraries or APIs from the underlying runtime such as Java or JavaScript.
jank
An emerging Clojure implementation focused on native performance and C++ interop.
JVM
Java Virtual Machine, the runtime that executes Java bytecode and also hosts languages like Clojure.
Paredit
A structural editing tool for Lisp languages that keeps parentheses balanced while you edit code.
Parinfer
An editor mode for Lisp code that infers and maintains parentheses structure from indentation and cursor movement.
REPL
Read-Eval-Print Loop, an interactive programming environment where you can run code snippets and inspect results immediately.
seq
Clojure’s abstraction for treating many collection types as a common sequence interface for traversal and transformation.
threading macros
Clojure macros like -> and ->> that rewrite nested function calls into a left-to-right pipeline style.

Reference links

Clojure runtimes and portability

  • jank clojure-test-suite
    Shared test suite used to measure portability of clojure.core across runtimes like Clojure, ClojureScript, Babashka, Basilisp, ClojureCLR, Phel, and jank
  • EnigmaCurry calc
    Example project used to discuss testing one Clojure codebase across Babashka, JVM, ClojureScript, and later Basilisp
  • babashka nbb
    Node-targeted scripting runtime mentioned as part of the wider Clojure ecosystem beyond the JVM

Editing and developer workflow

  • Parinfer
    Referenced as a tool that makes navigating and editing Lisp code structurally much easier
  • Ki Editor
    Mentioned as an editor built around AST-based movement and editing, extending the idea beyond Lisp

Concurrency and runtime references

Talks and essays

  • Rich Hickey - Are We There Yet
    Recommended as a talk that captures some of the deeper ideas behind functional programming and Clojure’s philosophy

Benchmarks and surveys

Article mirrors and caches