๐ how should I think choosing using kit or pedestal? I am new with clojure and trying to understand what study for a personal project. Main concern is DI / IOC and how easy it is to evolve the application. Feel free to suggest other options ๐
If you're new to Clojure, I would advise starting with the basics of web development before you get into the more complex stuff, since it's pretty different to anything you're used to I expect... Ring for the (Jetty) web server and basic request handling, Compojure or reitit for routing, Hiccup or Selmer for generating HTML, and go from there. You'll likely want either Component or Integrant to manage the lifecycle of things like web servers and DB connection pools. Take a look at https://github.com/seancorfield/usermanager-example and the linked examples that use different libraries.
Kit is great once you know what you're doing. As a beginner, there are a lot of moving parts in Kit and I do not recommend it until you understand the basics of the web stack. It is a curated set of libraries -- a lot of libraries -- and it's fairly opinionated.
Pedestal is a fairly different take on basic web stuff -- Ring is much, much more common -- but, again, interesting once you understand the basic web stack and want to explore interceptors instead of middleware.
๐ where can I read about clj docker best practices? Do people use nubankโs vessel? What else is there?
Depends, there's quite a lot you can do with server less now. For some use-cases, it doesn't matter, like say it's just some daily background job. You can often set some minimum reserved instances, for internal tooling that can be enough if there's only ever one user. Only if there were a rare spike it would have to start another instance and incur the cold start time. You can often use CrAc, and that tends to make it start almost instantly. You can native compile it with GraalVM, and that starts crazy fast. You can switch to a fast starting dialect like Babashka or ClojureScript, etc.
CrAc is probably the best, because it doesn't require adapting your code like native image or switching to another dialect do, and at least on AWS it's free when using their Java runtime.
Amazing, are there any downsides of using it though?
Not really. In theory "cost", as they have to store a cached checkpoint and it might be bigger in size, and then they need to load/unload it which can incur more network. But for AWS I know it's free if using the Java runtime.
TIL CRaC ! How long does it take to snapshot?
Any downsides? I.e can you snapshot in a โbad/incomplete stateโ ?
The snapshot is pretty fast, I mean it's mostly the time for your code to initialize. But it takes the snapshot when you publish a new version of your Lambda function. So the time to snapshot is never incurred by your users. The first request itself will be served from a restored snapshot.
You do have to be aware that things are getting restored. So if you have a: (def todays-date (DateTime/now)) This won't get refreshed. Similarly, a DB connection can't be restored, and so on.
You can use: https://javadoc.io/doc/io.github.crac/org-crac/latest/index.html to hook into the snapshot lifecycle.
What do you mean by "clj docker best practices"?
Most people develop "on the metal" -- since each Clojure project is completely independent and the dependencies are controlled by deps.edn and the CLI. The only dependency is a modern JDK -- at this point you might as well install OpenJDK 25, but if you want something less new, install OpenJDK 17 (the previous LTS release).
Yes, thanks! How do people deploy it though? I assumed docker is the most common way tbh
It depends. I think most folks build an "uberjar" (application) and deploy it on the metal or via a container. At work, we run everything "on the metal" since our servers are already virtualized.
As an insight into the community and its practices, you'll probably find our annual State of Clojure survey interesting: https://www.surveymonkey.com/results/SM-hht04mGydwZ6Nqr7N8vjCA_3D_3D/ -- that's 2024, and Q14 touches on deployment.
Public Cloud is the most popular deployment target, which I expect encompasses container-based deployment.
Locally, for dev, I use Docker for services but all my projects and REPLs and so on run directly on Linux locally.
I've seen:
โข two stage build with uberjar being shipped in a slim JRE-only container (more popular I think)
โข Clojure source is added to the container image, service is launched via clj (has advantages, but probably rare (?))
survey doesn't make it clear whether java -jar means somebody rsyncing an uberjar to a VM or if that's executed from within a Docker container running on some orchestrator
FROM azul/zulu-openjdk:21.0.0-jre-headless
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY target/my-app-jar.jar /usr/src/app/
CMD ["java","-jar", "my-app-jar.jar"]
# HTTP Server
EXPOSE 8082
# Clojure REPL
EXPOSE 7878
Like others have said, you only need the JVM. Thatโs a Dockerfile Iโve used. Itโs pretty straightforward.
Also, if you can run on the entire VM, that might be even simpler. I always thought that given the JVM, Docker doesnโt really add much.
The primary benefit of Docker originally was to ensure the app runs the same across systems.
One question though, why would I want to expose the REPL outside of the local env? I guess it would not be exposed outside of the VPC
yeah, that would be only for connecting from within the VPC using your tunneling solution of choice, with proper auth
VPC, only allow certain IPs to access, or just skip that
Re: Docker: I think the JVM does everything that Docker does (and better?) in terms of running apps pretty much identically across systems. But nowadays Docker has other conveniences: deployment, k8s tooling, etc.
โrunning appsโ: assuming your apps are purely JVM apps, of course ๐
The thing with docker os standardizing the OS dependencies too, this made me think or another question lol โ I couldnโt find clojure on sdkman, is there a similar tool available?
Clojure is โjust a jarโ, so in a way a level higher than sdkman (if my assumption for what sdkman does are correct); With the note that itโs โjust a jarโ that also compiles code ๐
Once your uber jar is compiled, you donโt need Clojure for just running the app.
The Install Clojure instructions work well in my experience across variety of systems (macOS and Linux) https://clojure.org/guides/install_clojure
Thereโs even a universal POSIX script, which is pretty neat. For local macOS installation, I personally use brew
Ohhhhh gotcha
That makes a lot of sense ๐
@raposo.felippe Which O/S do you develop on, normally?
(I ask b/c of your comment about Docker "standardizing the OS dependencies")
Usually local machine is OSX and deployment is on on linux
I have used ansible, puppet, chef, bash scripts, vagrant, plain sftp and restart process, rancher, k8s ๐คฃ Docker usually just works, specially using jib, jib just got me so spoiled that it was the first thing I looked for on clj land
Iโm pretty sure jib can work with Clojure, Iโve seen it done
(but I donโt have experience with it)
Is it intended to enable the application to be separated into multiple jars for the container layers, rather than relying on a single uber jar?
(from jib docs) > Now you donโt have to wait for Docker to rebuild your entire Java application In my experience, thatโs like a sub-second process, even with an uberjar in the 100s of megabytes. Trying to understand what jib offers over standard Docker.
(of course making the uberjar takes some dozens of seconds perhaps? but itโs not very long I think)
just found this, perhaps relevant? https://github.com/atomisthq/jibbit
https://clojurians.slack.com/archives/C0904S2QJ/p1758244473987849?thread_ts=1758223662.949409&channel=C0904S2QJ&message_ts=1758244473.987849 Not necessarily, I just wanted to run a single container to start with. Would be responsible for the application server and a http://temporal.io worker.
TYSM for your help, I owe you all many coffees ๐
Anytime!
I would start more with where you want to deploy it? Say you can use Heroku or AWS Elastic Beanstalk and it's basically just drop a jar. Or if you want to run it on a small Digital Ocean VM instance. Or if you want to so a AWS Fargate deployment. Or run it over AWS Lambda. Or you want full control of Load Balancing, VPCs, and what not.
Awesome, thanks! TBH I havenโt given it much of a thought yet, just went with the default I am using at current job. Wouldnโt a serverless strategy be non ideal since clj/java start up times are slow? Not sure what is the support of graalvm for clj too