beginners 2025-08-31

I haven't seen others ask or complain about this, so I'm unsure if I'm just missing something. The language itself is fascinating, and learning the language itself is really fun. However, learning the ecosystem around the language is (or seems to me, as a beginner) to be a big pain. I realize this isn't necessarily unique to the Clojure ecosystem. Learning the JavaScript ecosystem (Vite, Node, npm, etc.) from scratch would probably be a massive headache as well, although the barrier to entry is likely much lower due to its popularity. Am I exaggerating the pain of learning the Clojure ecosystem? Have I perhaps failed to find a good resource that covers it all from a bird's eye view for beginners? Deps.edn, Leiningen, cljs, cljs frameworks, etc. Coming from the JS ecosystem I suppose I'm spoiled, expecting things to work out of the box (e.g. getting the whole dev setup of a fullstack framework like Nuxt up and running with a single npm command). Perhaps the Clojure community sees this barrier as a feature, serving as a "normie filter"?

The https://replicant.fun is really well done; I'd recommend that as a starting point if you're wondering how to do web UI stuff in ClojureScript.

👍 1

"Learning the ecosystem" is a very loaded set of words that could mean different things to different people. I've been using Clojure for a decade, I myself wouldn't say that I've "learned the ecosystem". Same goes for any other language I have ever used, professionally or otherwise. I know enough things to do what I usually do. Everything else is relatively straightforward to find or figure out. > e.g. getting the whole dev setup of a fullstack framework like Nuxt up and running with a single npm command There are various templates for various tools for that. But I myself avoid them since it's usually easy enough to get started on my own and then I can make choices that I personally find to make the most sense. And I honestly don't see any reasonable benefit of being able to have something up and running with a single command. How often do you start new projects? Even if it was once a week, getting to a basic HTTP server with some API endpoints is like 2 minutes once you understand how to do it and what the main components are. Now that we have LLMs, even that little time could be brought down significantly. > Perhaps the Clojure community sees this barrier as a feature, serving as a "normie filter"? We don't want to filter people based anything other than things that don't adhere to our Code of Conduct. Regarding tools and "one command to run everything" I believe what I wrote above tackles it. Regarding "all or nothing" frameworks, the community in general shuns them because it's pretty much always a choice towards easiness and against simplicity. Ruby on Rails has an incredibly fitting name - yes, it's fast to use if you want to go where the rails lead you. But as soon as you want to do anything differently, there's a derailment. Django is the same - good luck doing something that it wasn't built for. Or the infamous create-react-app - a guaranteed shitshow if your project was using it for years because "it took just a single command" but ended up hitting a brick wall that would require getting rid of it. And so on and so forth. Simple is better. Short term for understanding, long term for everything else.

➕ 3

I'm not sure if you'll find a single document describing everything. I think the typically clojure users prefer composable libraries over comprehensive frameworks. Although "just learn this one framework" gets you up and running fast, many of us have been burnt by frameworks in the past and prefer composing individual pieces. Thus, I feel like learning the ecosystem also requires learning the pieces.

I'll start by assuming you've already read the official getting started guide https://clojure.org/guides/getting_started and the pages linked from there, but I'll also point to https://clojure-doc.org/articles/tutorials/getting_started/ which specifically talks about Leiningen vs CLI/`deps.edn` and why/how we got here. You don't mention which O/S you're on or what editor you're already used to, which might help us point you at specific online tutorials etc. As Eugene and Lasse noted, Clojure leans toward (lots of) simple, composable tools and libraries allowing developers to pick'n'choose -- which is certainly more of a burden than having a single, all-encompassing stack/toolset that you can use for "everything" and which has a single source for documentation and help. But the Clojure community favors flexibility over frameworks.

I had not seen the http://clojure-doc.org website. That seems helpful! I'm comfortable with emacs, even though I come from a VSCode background due to the JS ecosystem (with emacs keybindings, of course). Ironically I'm on Linux, yet my greatest weakness is my impatience with spending time on things that aren't writing actual code. I absolutely get behind the simplicity of composability. I suppose the pick-and-choose aspect is the difficult part, when one isn't familiar enough with the things to know what to pick, especially when there are so many options. I struggle with that already in the JS ecosystem. Analysis paralysis, eh? Perhaps leveraging LLMs to explore libraries and various configs is the way to go.

Or asking humans here perhaps? 🙂

Both Emacs + CIDER and VS Code + Calva are well-maintained approaches to Clojure development via a connected REPL -- an idiom that is unique to Clojure and also has a learning curve: there are some good videos out there showing a REPL-driven workflow. VS Code + Calva probably has the easiest on-ramp of any editor package for Clojure -- it's what I use every day, on Windows with WSL2 (so all my development happens on Linux).

I remember similar feelings when learning Java something like 15-20 years ago. It felt like there were a dozen different libs for just parsing XML and no idea which one was the "correct" choice. But the upside of picking individual libraries is that usually you can fix a poor choice later, without rewriting your whole app. And making an educated guess let's you experiment and get a feel if you chose poorly and better understand the choices.

I instantly fell in love with paredit and CIDER while reading through Brave Clojure. The language itself is really fun to work with. Even Hiccup syntax seems really cool. EDN instead of XML? Yes, please. (Although I'm unsure how often I would actually be treating my UI elements as data.) I think I might be mostly worried about the front-end web development. Things like hot module reloading and batteries-included UI frameworks (like Nuxt UI). I realize batteries-included complexity goes against the spirit of Clojure, and I might be completely wrong here, but I suspect that when it comes to HTML/CSS building a UI system from scratch is extremely time-consuming.

> Although I'm unsure how often I would actually be treating my UI elements as data. In my experience, it's never about storing that data somewhere. But it is sometimes about post-processing Hiccup data that got returned from somewhere. So it is useful, to a degree. And to me it just looks much nice, much more pleasant to work with. > Things like hot module reloading That's built into at least shadow-cljs, works like a charm. > batteries-included UI frameworks You can still use JS frameworks from CLJS. But there could be a decent amount of friction, especially if they expect you to use some preprocessor, like some webpack plugin. That being said, there are frameworks like this in Clojure, although I myself have never felt any need to use them. > I suspect that when it comes to HTML/CSS building a UI system from scratch is extremely time-consuming. Depends on what you're building. For something small, just to play around - it doesn't matter at all. And if you need a comprehensive solution that lets you create modern apps that will be used by many people - yeah, sure. But there are dozens and dozens of projects out there that let you deal with this. It doesn't matter that you will be using them from CLJS - HTML/CSS won't get in the way. It does't have to be some JS- or TS-only library that's a PITA to make it work with any other language. And there are also a few CLJS projects as well.

🙏 1

I don't think you're exaggerating the pain, because I've seen so many other beginners have the same struggles. The problem is the ecosystem is vast, and there's no one set of libraries or frameworks that have a strong majority in popularity. And maybe because the community is small, it ends up that none of them have a lot of tutorials, books or articles written about them to help beginners start out. My suggestion is to ask here on slack to find help.

🫡 1

Thanks for the responses, everyone. It helped a lot!

Things that are in vogue are: Tooling: • Clojure CLI – Run Clojure, manage deps • Tools.deps – Define/manage dependencies • Tools.build – Automate builds & packaging • Cider – Emacs Clojure IDE tools • Calva – VS Code Clojure support • Cursive – IntelliJ Clojure plugin • Clj-kondo – Fast linter • Clojure-lsp – Editor features (autocomplete, nav) • Flowstorm – Time-travel debugger • Portal – Data viewer/inspector • Shadow-Cljs – Build ClojureScript apps Web: • Ring – Core HTTP library • Hiccup – HTML with Clojure data • Compojure – Simple routing • Reitit – Fast, feature-rich routing • Next.jdbc – SQL DB access • Reagent – React wrapper for ClojureScript • Replicant – Render UI (DOM/HTML) from data (alternative to react)

🙏 2

You can kind of make your way through that list and research them one at a time. It's not the whole ecosystem, but it's a good starting point.

And there are dedicated channels for most of those here, so you can ask deeper questions if you get stuck: #tools-deps #tools-build #cider #emacs #calva #vscode #cursive #clj-kondo #lsp #flow-storm #portal #shadow-cljs #ring #hiccup #compojure #reitit #sql #reagent #replicant

🫡 1

I am sure my response is superfluous at this point, but my 2c is that with Clojure, learn to love the "https://en.wikipedia.org/wiki/Bricolage." While it can be frustrating in the beginning, once the initial bumps are over and you feel comfortable putting together the basic building blocks of a program/app/piece of software, I think it's something special you'll never get out of running a single NPM command. In the process, I think you will find you learn things about the platform that not even experienced JS developers know about: because they have spent their careers copy-pasting stuff from Stack Overflow posts, ChatGPT, etc etc. And I can second what people have said above: please lean on the community here, it is absolutely one of a kind!

👍 1

Hi beautiful Clojure Community 👋 I started learning Clojure 3 days ago, moved by the example of @pavel.klavik and Uncle Bob, I'm having a lot of fun so far and I genuinely enjoy the language. I've been experimenting with GraalVM, as a relevant part of what I do, is building middleware and data parsers/transformers, and not just backend services or long-running apps. I find Clojure Data Oriented Programming principles very much in line with what I want to build. In my experimentation, I was happy to be able to build small Clojure programs to (1.) native-image from GraalVM and (2.) self-contained app-images packaged with JRE using jpackage But in my pursuit I found that not everything in Clojure may be compilable with GraalVM as it leverages AOT in order to build this very efficient images. Clojure uses a lot of reflection and dynamic loading (apparently). I bring some beginner questions today if you don't mind me asking 🙂 • What has been your experience with Clojure when building native-images with GraalVM? • Clojure/JVM has some (alot?) startup overhead (check attached image), how do you workaround it? • What's your position on Clojure speed? • Is Clojure a web-app/server "only" programming language? Thank you so much 🙂 regardless I'm much happier writing Clojure than plain Java 8 (yes I'm still in the trenches) and I feel I found something new to be excited for. 🙏 Image Legend: The running times of two Clojure Hello Worlds. Top: A packaged Clojure Hello World running as a self-contained, JRE included App-Image - built with jpackage. Bot: A packaged Clojure Hello World self-contained native image (no JVM) built with GraalVM 21.

To clarify, as your last message suggests a potential misunderstanding: Babashka has nothing to do with Python. Babashka is essentially a Clojure interpreter written in Clojure that is compiled to a native binary by GraalVM.

> What has been your experience with Clojure when building native-images with GraalVM? graalvm has reflection config, which facilitates some of the more dynamic stuff > Clojure/JVM has some (alot?) startup overhead (check attached image), how do you workaround it? <https://clojure.org/guides/dev_startup_time> might help some, depending on context also, I often have a REPL running for a days at a time, and that amortizes pretty nicely over some other languages where I have to restart a program and rebuild a bunch of state for every change to the code > What's your position on Clojure speed? fast enough for me, and in many contexts, I'm happy to trade a few milliseconds of CPU time (even when it stacks up) for some of the niceities I find, especially when changing an existing codebase > Is Clojure a web-app/server "only" programming language? no Other notes: • if you want really fast startup time/a more "CLI scripty" type experience, babashka might be worth looking into (which is a graalvm-compiled, interpreted clojure flavor) • for discussion specifically around graal, you might want to check in at #graalvm - there are some resources there and even specific 'tooling' for using clojure with graal

Thank you so much for this feedback it is super useful. I will look into the resources you showed me. I'm really happy that there are more options than the ones I've currently read about related to Graal. I'm super excited for what's ahead, thank you Bob 🙏

if you check the #graalvm channel info, there's these helpful link shttps://github.com/clj-easy/graal-docs and https://github.com/BrunoBonacci/graalvm-clojure.

When you say building middleware and data-parsers/transformers... What does that mean? Generally Clojure is fast enough in terms of latency and scale for most real world use-cases. And can be optimized further by moving some of the hottest paths to Java, the GPU, or native if really really needed. Startup time is the only thing that can be said to be pretty slow. But if that's an issue or not is very use-case dependent. For example, for AWS lambda, you can use snapstart and get pretty decent lambda startup times. For other use cases you can restrict yourself to the subset of Clojure that works well with GraalVM like you said. For some use-cases you can switch to the Babashka runtime, the Node runtime using ClojureScript, or the Python runtime using Basilisp. There's a LLVM runtime being built called #jank still not ready to use but should be soon. So you have a lot of options if you need fast startup times, but each have some trade-offs.

@didibus, I have for example a tool made in Java which reads thousands of XML files with geometrical data per day, transforms those shapes and outputs a result in JSON format. It usually runs in less than one second depending on how many files I have to go through. It's one of the core jewels of a beautiful project I'm part of in my company. I believe you and I know Clojure is fast! Most benchmarks out there for Clojure show it as one of the top performs for CPU-bound tasks (in native mode).

For example, for AWS lambda, you can use snapstart and get pretty decent lambda startup times.
Really good advise, thank you. Yeah I work with AWS Lambdas a lot too.

Does that need to start fast? If it runs once per day, what's another 1 second to wait for initialization?

I believe in native compiled, Clojure will run slower, it'll only start faster. But it depends a bit, the native compiled binary is instantly warm, fully compiled, but the compilation optimization was a best guess by Graal. In JIT compilation, it'll run initialization and then it'll need to warm up as code paths are taken the JIT will use the actual runtime behavior to decide how to compile in the most optimal way, and if the behavior changes dramatically it'll recompile a different way. Generally that means the JIT gives you better runtime performance, at the cost of a slower startup and warmup period.

If you use the Enterprise edition of Graal, not the community edition, it comes with support for profile-guided AOT compilation. You can run a workload and it'll output a profile. Then recompile using that profile so that the "guess" is based on that workload.

Also, IANAL, but the enterprise edition is free to use for certain commercial applications. You can't use it to generate binaries or jpackage that you sell to users. But you can use it to generate binaries, jpackage or other modes to run for internal purposes (even in commercial settings).

> Does that need to start fast? If it runs once per day, what's another 1 second to wait for initialization? Sorry maybe I wasn't clear, I meant - it reads thousands of XML files per day, but it runs multiple times a day with a different random number of files (between 10-150).

👍 1

> Generally that means the JIT gives you better runtime performance, at the cost of a slower startup and warmup period. I feel you. But if you have a tool which takes between 0.3ms-2 secs to run, but the startup overhead is around 200ms which decision would you make?

> But if you have a tool which takes between 0.3ms-2 secs to run, but the startup overhead is around 200ms which decision would you make? It really depends on the sensitivity of my use-case. What is waiting on the output and can it wait 200ms more?

Say you wanted to make a jq or grep like Command Line tool. Then I'd be annoyed as a user if I'd have to wait an extra half to a second. I'd want something that feels near instant. So I'd look into the alternatives I mentioned. But if I had a CI/CD job that needs to run on deploy, I'd be fine with just ClojureJVM and have it take an extra 0-1 sec.

Also, IANAL, but the enterprise edition is free to use for certain commercial applications. You can't use it to generate binaries or jpackage that you sell to users.
> > But you can use it to generate binaries, jpackage or other modes to run for internal purposes (even in commercial settings). I just ChatGPTed it and will confirm this but if I use GraalVM CM + its corresponding native-image I should be able to use my package commercially since it is GPLv2 But thank you again, you are a pool of knowledge, I will for sure take this into consideration. My company does run GraalVM in other projects so I'm sure they already are licence cleared on that, or they can get that cleared of with ease. > It really depends on the sensitivity of my use-case. What is waiting on the output and can it wait 200ms more? It's a fair point. The product is time-sensitive as the user is waiting for visual changes on the client side. This middle-ware component sits at the middle of the process. But 200ms (startup overhead) would correspond to 1%-1.5% of the total time the complete run requires, so definitely not the bottleneck in the big picture. Removing the startup overhead would therefor decrease the total time this system needs to run by 1%-1.5%.

Thank you so much by the way, I find this conversation super productive.

Ya, I believe GraalVM CM you can also distribute your compiled binary and charge users. With the enterprise edition (which will create an even faster binary), you can only distribute binaries to users if you don't charge them. But if you are wanting to use it internally for say some ETL jobs, running a web server, a microservice, running some Lambdas, etc. I think you are allowed to do all that, even if it's for commercial use. Like you can sell a subscription to a SaaS that runs with compiled binaries of the enterprise edition, because that does not redistribute the binary.

The product is time-sensitive as the user is waiting for visual changes on the client side.
Ya, I feel if a user is waiting for it and stuck waiting, like they see "loading" and have nothing else to do in the meantime. Then I would want to get rid of the startup cost and even warmup cost as much as possible. If that loading will be taking 5+ seconds already, maybe I'd fine fine adding another 200-1000ms on top haha, since at that point it's already "kind of slow", it's hard as a user to tell the difference between 5sec and 6 sec, but it's easy to tell the difference between 80ms and 800ms.

If you don't need as good runtime performance (like where Python or Ruby would be fine), babashka is a great option as well:

> time clojure -M hello.clj
Hello World
clojure -M hello.clj  0.69s user 0.04s system 190% cpu 0.388 total

> time \bb hello.clj
Hello World
\bb hello.clj  0.01s user 0.01s system 78% cpu 0.028 total
The second one is babashka, first one is Clojure running as a script.

I'm definitely using babashka for all my bash stuff xD I really love the concept and I hate writing bash opposed to Clojure. It may also in fact change a lot of my decision making process when writing new components. But when it comes to runtime and CPU computation I'm definitely sticking with JVM family opposed to Python (which I also work with daily but in different project) or other interpreted languages. Clojure makes a lot of sense for me because I'm already familiar with the JVM ecosystem and it will (hopefully) enable me to become better at what I do. I'm also genuinely having a lot of fun writing Clojure. I've also been reading on Java 24 https://openjdk.org/projects/leyden/ and this is probably what I'm looking for in the future. 🙂

👍 1