A complete Clojure project you can leap from

Published 2016-07-05

The best way to learn any programming language is to start a project to solve some problem. The problem drives you forward, getting you to think about how to apply your new-found knowledge, and you automatically learn the language along the way.

One of the questions we hear a lot from people wanting to dive into Clojure is, "How do I set up a Clojure project?".

Many beginners have to invest too much of their time learning the tooling rather than the language.

That's why projects like Luminus are so useful. You can get set-up with the minimum of fuss and focus on working on your problem (while learning the language).

Another worthy mention is Mastodon C's suite of Clojure projects, who open-source a lot of complete real-world projects.

By their very nature these projects are full of opinions of what general problem to solve, which libraries to use and how to organise your code. That's why it helps if there are a selection to choose from.

Introducing Edge

Edge is a project from JUXT that helps you get started with a simple website, API or micro-service. You can put it in the same mental box marked 'frameworks', along with Luminus, Hoplon, Chestnut and Arachne.

Edge is not a template system, you don't generate the project with lein or boot. You just git clone it and type boot dev to run it. As things are moving fast (both in Edge and in the Clojure world as a whole), we think it's good to retain the ability to merge Edge updates to your own project.

There's not much code in Edge, around 500 lines, but it's packed full of features and built on solid engineering principles like loose coupling', single responsibility, don't repeat yourself and separation of concerns.

Some of our decisions need explaining, so here's goes.


Edge uses Stuart Sierra's infamous component library for structure.

On balance, we prefer it to mount, for many of the reasons explained here. (We much prefer both component and mount to the traditional practice of sprinkling defs in random namespaces.)

Web libraries

Edge uses bidi for URI routing and yada for handling web requests, both JUXT libraries.

Good websites and APIs should make liberal use of hyperlinks, but you don't want those hyperlinks to get stale and break. While bidi can be harder to learn and use than Compojure, it allows you to iterate your API design freely. Hardcoded URIs can be a form of implicit coupling, a short-cut to code-rot. As every true developer knows, every time you add an implicit coupling to your code-base a fairy dies — so using bidi also helps to keep fairy populations healthy.

Edge makes a great springboard for a micro-service. It contains a small RESTful phonebook app, and there's even a Swagger UI included, so you can communicate your API design to your team. And because it's built with yada, clients will think you're an HTTP protocol guru.


Real-world projects invariably need some application configuration mechanism to specify the details of the operating environments in which they run.

Again, Edge uses our own Aero library - it's easy for small projects that just need a single configuration file, based on Clojure's own EDN format. Plus Aero throws in some features that allow it to scale as your project evolves. Maybe we're a little biased but we think this is the most ideal balance of trade-offs for configuration.

Network REPL

Edge launches a network REPL, so you can remote debug your service while it's running. The service is bound to localhost only for security reasons, the idea is that you connect to it via ssh forwarding.



Since Edge is built with yada you'll have good security defaults built-in: parameter validation, HSTS, flexible authentication, ABAC/RBAC authorization and access control options.


Edge has chosen to adopt boot, rather than Leiningen (although we wouldn't say no to a Pull Request!)

Web projects are becoming more complex these days, with the need to support for ClojureScript and CSS compilation, flexible packaging and deployment, and other concerns. We find boot is somewhat harder to use but more flexible than lein, and allows you to run more within a single (expensive) JVM. While we are still in a phase of experimentation, boot makes sense.


Edge is agnostic about databases. There are so many choices from traditional relational databases to graph and key-value stores. Since there are no stateful objects, there is no need for an ORM and no need for Edge to offer opinions as to how you go about persisting data.

There is, however, a database component that works as a place-holder for whatever you want to use.

HTML templates

Hiccup is great for generating HTML snippets, but for whole pages we prefer templating solutions. We've picked Selmer for Edge, but it is easy enough to unpick and go with an alternative such as enlive or Stencil (Mustache).

Selmer is a Django-inspired template library. We like its rich library of built in functions and the ease of adding custom ones.


As you might expect, Edge has all the modern boot-powered ClojureScript tooling. You don't have to care how it works, you can just start launch a browser, hack the .cljs code and see your app take shape. Automatic browser reload, HUD and browser REPL are built-in too.


Phonebook form

These days, all the cool kids are using CSS compilers like Less and Sass, and for Edge we've opted for Sass. The process is seamless: you edit the files in Edge's sass directory and voila, your changes are automatically reflected in the browser.

When to use Edge

Edge is designed to help you get up and running quickly. For that reason it's ideal for dojos, training courses and hackathons. It's great for knocking up a quick micro-service to impress your friends (or your boss!).

The best thing is you'll have something up-and-running in minutes.

How to use Edge

Here's how to get started:

git clone https://github.com/juxt/edge
cd edge
boot dev

Wait until you see the message:

INFO  edge.server - Started web-server on port 3000

Then browse to http://localhost:3000

There's a README to explain how to launch Edge with CIDER or other IDE. If you're not using those, you can always connect a REPL to port 5600. Either way, you can type (reset) to get quick code refresh.

submit to reddit