Organize code with ns and require, keep name origins visible, and use imports only where they improve clarity.
Namespaces are where Clojure’s small syntax pays off. They give names context, keep function origins visible, and let you write concise code without scattering imports everywhere.
For a Java engineer, the closest analogy is “packages plus imports,” but that comparison is incomplete. A Clojure namespace is also a live mapping from symbols to vars and classes. That is why namespace hygiene has such a strong effect on readability.
nsMost Clojure source files begin with a single ns form:
1(ns my.app.orders
2 (:require [clojure.string :as str]
3 [my.app.money :as money])
4 (:import [java.time Instant]))
This does several things at once:
By convention, a file maps one-to-one with one namespace. That is one reason Clojure codebases are usually easy to navigate once the naming convention clicks.
:require Is The Main ToolIn modern Clojure code, :require does most of the work.
Common patterns:
1[clojure.string :as str]
2[clojure.set :refer [union intersection]]
3[company.application.user :as user]
Use them for different reasons:
:as creates a short alias like str/trim:refer brings selected vars into the current namespacerequire without extras just loads the namespaceThe safest default is usually :as. It keeps origins visible at the call site:
1(str/lower-case "DEV@EXAMPLE.COM")
That is easier to review than an unqualified lower-case whose origin you must remember.
:refer Selectively:refer is useful, but it should feel intentional.
Good cases:
Less good cases:
ns form constantlyFor Java developers, think of :refer as “import static, but use with restraint.”
use Fits TodayYou will still see use in older material and some legacy code. It refers public vars into the current namespace automatically. That broad auto-referral is exactly why many teams avoid it in new code: it makes name origin harder to see and increases collision risk.
So the practical guidance is:
use does so you can read older codens with :require and selective :refer in new codeThat is a style recommendation for maintainability, not a statement that use has vanished from the language.
Aliases are one of the most useful everyday tools in Clojure:
1(ns my.app.billing
2 (:require [my.app.money :as money]
3 [my.app.tax :as tax]))
4
5(defn invoice-total [invoice]
6 (-> invoice
7 money/subtotal
8 tax/apply-tax))
The aliases make origins explicit without repeating long fully qualified names.
This is a major part of how Clojure stays readable even though functions are globally named by namespace and var.
:as-alias Helps Qualified KeywordsCurrent Clojure also supports :as-alias, which creates a namespace alias without loading the namespace:
1(ns my.app.invoice
2 (:require [company.application.user :as-alias user]))
3
4{::user/id 42}
This is especially useful when the alias is mainly there to qualify keywords for data, specs, or destructuring, rather than to call vars from a loadable namespace.
For Java readers, this can feel surprising at first because the alias is helping with the shape of data, not with method calls.
:import Is For Java Classes, Not Clojure CodeIf you need Java interop, use :import for classes:
1(ns my.app.clock
2 (:import [java.time Instant ZoneId]))
3
4(defn now []
5 (Instant/now))
You do not use :import for Clojure namespaces. That is what :require is for.
A healthy default is to import Java classes only when it improves readability. Fully qualified class names are also fine if the use is rare and you want to keep the ns form smaller.
The Java comparison is helpful up to a point:
:require + :as ~= import plus alias-like shorthand:import ~= Java class importsBut Clojure goes further:
ns formThat unified setup is one reason a good ns form tells you a lot about a file before you even read the functions.
If you want a strong default style:
ns:require with :as:refer narrowly:import only for Java classes you actually useuse as something to understand, not as your defaultThat set of habits will make your code much easier for other Clojure developers to scan.
require