A few more thoughts have come to mind after writing the original post.
I realized that I didn't talk about the clojurescript side of things.
Another clojurescript advantage is that it comes with immutable datastructures built in. No need to pull in immutable.js.
If you're going to use react for building views, there are plenty react wrapper libraries to choose from in clojurescript. My personal favorite is Reagent. I find the Hiccup HTML syntax great too as that eliminates the need for a separate step to transform your JSX to HTML.
You'll also get to share code between your backend and frontend with cljc. This isn't like the false promises people made when node.js first came out with sharing code between client and server. You really can share code on client and server.
One way to go about this is to develop your business and domain logic in
.cljc files. Then you can leverage clojure's
edn data format or preferrably transit json (because it's faster) to send data back and forth.
Something else I've tried is writing data validations in
.cljc files. Then you can immediately validate data on the client side to give your users instant feedback and validate it again once it gets to the server with the same code.
One last thing about clojurescript. The tooling is fantastic. We have dev cards and fig wheel. I've even heard stories from people that have developed front end components in a TDD style for hours without needing to look at a browser.
Another thing I realized since writing the original post is the lack of full stack, Rails like web frameworks is not a big of a deal as I thought, mainly due to the popularity of microservice architectures. Microservices are popular now which means teams end up writing many small services that powers a front end single page application.
Anyway, these are my updated 2017 thoughts. Back to the original 2015 post.
I wrote an article that tried to compare Node.js and Clojure for web development in 2014. When I migrated my blog from Wordpress to Jekyll today, I deleted a lot of old posts, including the 2014 version of this one. I didn't feel like it was an honest and objective comparison. Also, since then I've gotten a much better understanding of the strengths of the Node.js and Clojure communities and ecosystems, so here are my thoughts now.
The first thing most people notice when they join the Clojure community coming from another language is that there are no web frameworks. No such thing.
You might consider Luminus to a framework of sorts. It even says on the homepage that it's a Clojure micro-framework! But really it's just a template for web applications in Clojure. It's a great starting point for beginners, but that doesn't make it a framework.
I define a framework to be like a shell. A shell that standardizes how things should be done and easily enables people to snap pieces they want in (for the general case). I'm sure somebody out there is already poking a holes at my definition, but hear me out.
The reason Ruby on Rails is a framework, other than it giving you everything and the kitchen sink, is because you can reasonably expect that people using Rails would also be using ActiveRecord, ActiveSupport, Rack, and ActiveWhateverElse.
What this enables is that other people can build on top of this expectation. For instance, the devise gem allows you to just easily drop form-based authentication into your application. You don't have to write functions that call your database and do the CRUD for your users. It just works for 90% of the use cases.
This is also why I think of Express.js as a micro-framework. It enables a similar story for authentication on the Node.js side with passport.js. The cool thing about passport.js is that there are 307 authentication strategies as of today that you can just snap in.
What about templating? In Rails it's usually as easy as dropping in another gem and renaming your files. In Express, you add another dependency and call a few functions to hook it up. Then you put your templates in a standard path and you're good to go.
In Clojure? You have to do a lot of work if you want to switch templating libraries halfway through. I'm not talking about changing your template/view code either. That's a given.
The work you have to do is due to how there's no standard interface to hook up your templating engines like in an actual web framework. Let's say you start out using hiccup for your templating. Hiccup templates are just Clojure datastructures, so they live in the src directory of your code.
Then it turns out the team of designers that just joined your team don't like and don't want to learn hiccup even though it's just HTML but simpler syntax. So you decide to switch to using Enlive. Or maybe moustache/handlebars. Anything to make the designers happy.
The work to switch your templating library can involve re-structuring the entire codebase. Remember, your hiccup templates live with your code! You have to figure out where to put your new templates (likely just on the classpath somewhere) and incorporate it into your code base without a standard interface to hook it in.
The Clojure community embraces tiny modular libraries to a fault. In my mind, there's a false dichotomy between going full monolith like Rails and composing each library yourself. It's not black and white like how most of the Clojure community makes it out to be.
I think the Node.js community almost gets the balance between full framework and tiny libraries right. Express.js doesn't give you everything and the kitchen sink. And everything is in its own module. If you need specific middleware, for instance form body parsing, you can include it and plug it in. And I think the key difference is that a framework gives you a standard to plug things in. Think Micro-USB. And having no frameworks at all reminds me of when we all had dumbphones and each phone had its own proprietary charger.
Check out the TechEmpower Benchmarks and make your own choices based on what workload fits your application the best.
One more thing to consider is that Node.js drops down to native C libraries to some of it's work like making requests. If your workload is primarily waiting on things to happen, it's something to also keep in mind.
If you're building a website, Node.js is the right tool for that job. Due to lack of web frameworks, the server-side rendering, CRUD, type of web application is going to be slower in dev time to make in Clojure. That has been my experience 100% of the time. If you're going to do CRUD, don't reinvent the wheel. Use a framework.
If you're building an API or service that isn't computationally intensive, like waiting on network calls, then Node.js is probably the right tool. Let's be honest. Most of the time spent in your web application is just waiting on a record from a database and sending it back to a user. Node's async by default is good for the majority of these cases.
If you're building building an API or service that isn't computationally intensive, but hate callbacks, then use Clojure and leverage core.async.
If you're building an API or service that is computationally intensive, like doing machine learning on a large dataset, then Clojure is the right tool.
If you need to leverage the JVM... then Clojure. Hadoop? Apache Spark? Parallel computing? Clojure is surely the tool here.
If you want to attract better engineers (on average) and retain more talent by spicing things up, then go Clojure.
Use the right tool for the job and what makes you and your team happiest. Iterate fast and most importantly, build something people want.