← Back to Blogs
HN Story

ClojureScript 1.12.145: Native Async/Await Support Arrives

May 11, 2026

ClojureScript 1.12.145: Native Async/Await Support Arrives

The ClojureScript team has announced the release of version 1.12.145, bringing one of the most requested features in the ecosystem's history: native support for async and await. By targeting ECMAScript 2016, ClojureScript can now emit native JavaScript async functions, fundamentally changing how developers handle asynchronous operations when interfacing with the modern web.

For years, the ClojureScript community has navigated the tension between the language's functional purity and the asynchronous nature of the JavaScript runtime. While powerful abstractions existed, the lack of a first-class language construct for async/await often required developers to rely on third-party libraries or complex promise chains. This update removes those barriers, allowing for cleaner, more readable interop with Browser APIs and popular JS libraries.

Implementing Async Functions in ClojureScript

The new functionality is implemented via a compiler hint. By marking a function with ^:async, the ClojureScript compiler will emit a standard JavaScript async function. Within these functions, the await special form can be used to pause execution until a Promise is resolved.

Consider the following implementation:

(refer-global :only '[Promise])

(defn ^:async foo [n]
  (let [x (await (Promise/resolve 10))
        y (let [y (await (Promise/resolve 20))]
            (inc y))
        ;; not async
        f (fn [] 20)]
    (+ n x y (f))))

This support extends to testing frameworks as well, enabling developers to write asynchronous tests without the boilerplate typically associated with promise-based callbacks:

(deftest ^:async defn-test
  (try
    (let [v (await (foo 10))]
      (is (= 61 v)))
    (let [v (await (apply foo [10]))]
      (is (= 61 v)))
    (catch :default _ (is false))))

The Interop Trade-off: Native vs. CSP

The introduction of async/await has sparked a healthy debate within the community regarding the "right" way to handle concurrency in ClojureScript. For a long time, the gold standard has been core.async, which implements Communicating Sequential Processes (CSP) via channels.

Some developers argue that the CSP model is superior because it provides a more robust pattern for handling complex asynchronous flows than the JS-style async/await keyword. As one community member noted:

"Seems like wrapping async await functions with CSP was a better way to handle this. Clojure already had a nicer pattern for this."

However, the primary driver for this release is interoperability. The Clojure survey indicated that native async support dominated the list of desired enhancements. By providing native async/await, ClojureScript eliminates the need for additional dependencies when interacting with modern Browser APIs, making the language more accessible and reducing the "dependency tax" for simple asynchronous tasks.

Technical Hurdles and Community Context

The path to this feature was not simple. According to community insights, previous attempts to implement native async support were hindered by the need for deep changes across the ClojureScript compiler. Some developers believed that macros from libraries like Promesa provided sufficient convenience, or that expression-oriented languages were inherently a poor fit for the async/await syntax.

Despite these objections, the persistence of contributors—specifically Michiel Borkent (borkdude)—has brought the feature to fruition. This release represents a pragmatic shift toward embracing the host environment's native capabilities to improve developer experience.

Looking Ahead: Divergence and Adoption

The addition of await introduces an interesting linguistic divergence. Since await is already a keyword in clojure.core, ClojureScript is introducing a feature that does not have a direct equivalent in Clojure (JVM). This raises questions about how far the two implementations will diverge to accommodate the specific needs of the JavaScript runtime.

While some users express concern that this makes ClojureScript feel less like "Clojure on JS," others see it as an essential evolution. As the web evolves, the ability to seamlessly integrate with the native asynchronous primitives of the platform is no longer a luxury—it is a requirement for modern frontend development.

References

HN Stories