Browse Learn Clojure Foundations as a Java Developer

Namespaces and Requires

Organize Clojure code with ns, require aliases, selective refer, Java imports, and namespace hygiene that keeps symbol origins clear for Java engineers.

Namespaces are where Clojure’s small syntax becomes maintainable at project scale. They give symbols context, make dependencies visible, and let a file stay concise without hiding where important functions come from.

For a Java engineer, the closest analogy is “package plus imports,” but a Clojure namespace is more active than a Java package declaration. It is a live mapping from symbols to Vars and classes, and that mapping affects how every form in the file is read.

The ns Form

Most source files begin with one ns form:

1(ns my.app.orders
2  (:require [clojure.string :as str]
3            [my.app.money :as money]
4            [my.app.tax :as tax])
5  (:import [java.time Instant]))

That form establishes the current namespace and declares the code this namespace depends on. A good ns form works like a table of contents for the file.

Part Purpose Java comparison
my.app.orders Current namespace Package-like location
:require Clojure namespace dependencies Imports plus aliases
:as str Local alias Short qualified name
:import Java class imports Java import statements

By convention, one source file usually maps to one namespace. The namespace my.app.orders normally lives at src/my/app/orders.clj.

Prefer :require With :as

The most common dependency pattern is an alias:

1(ns my.app.billing
2  (:require [clojure.string :as str]
3            [my.app.money :as money]))
4
5(defn normalized-email [email]
6  (some-> email str/trim str/lower-case))

Aliases keep origins visible at the call site:

1str/lower-case
2money/format-cents

That is easier to review than unqualified names whose origins must be remembered from the top of the file.

Use :refer Deliberately

:refer brings selected Vars into the current namespace:

1(ns my.app.report-test
2  (:require [clojure.test :refer [deftest is testing]]
3            [my.app.report :as report]))

That is reasonable in tests because names like deftest, is, and testing are part of the testing vocabulary. It is less helpful when business functions lose their origin:

1;; Harder to review when many namespaces refer unqualified names.
2(calculate-total order)

Default to aliases in production namespaces. Use :refer only when the unqualified name genuinely improves readability.

Treat use as Legacy Style

Older Clojure material may use use:

1(use 'clojure.set)

The problem is that use broadly refers public Vars into the current namespace, making origins harder to see and collisions easier to create. Modern code usually prefers explicit :require forms:

1(ns my.app.permissions
2  (:require [clojure.set :as set]))
3
4(set/intersection user-permissions required-permissions)

Learn use so you can read older code. Do not make it your default style.

Java Class Imports

Use :import for Java classes, not Clojure namespaces:

1(ns my.app.clock
2  (:import [java.time Instant ZoneId]))
3
4(defn now []
5  (Instant/now))

For rare uses, a fully qualified class name can be clearer than adding another import:

1(java.util.UUID/randomUUID)

The same rule applies as in Java: import when it improves readability; avoid imports that make the top of the file noisy.

Qualified Keywords and :as-alias

Clojure also uses namespace names to qualify keywords:

1{:user/id 42
2 :user/email "dev@example.com"}

Sometimes you want an alias for data qualification even when you do not need to load Vars from that namespace:

1(ns my.app.invoice
2  (:require [my.app.user :as-alias user]))
3
4{::user/id 42}

For Java readers, this is unusual: the alias is helping describe data shape, not method access. The payoff is that map keys can carry stable, collision-resistant meaning.

Namespace Hygiene Checklist

Decision Strong default Why it helps
Clojure dependency :require ... :as alias Keeps origins visible
Test vocabulary selective :refer Reduces noise where names are standard
Java class :import Keeps interop concise
Rare Java class use fully qualified class Avoids import clutter
Legacy broad import avoid use Prevents hidden origins and collisions
Data-only alias :as-alias Supports qualified keywords without loading Vars

Common Mistakes

Mistake Better habit
Importing Clojure namespaces with :import Use :require
Referring many business functions unqualified Use aliases so origins stay visible
Treating namespace names as arbitrary labels Match namespace and file path consistently
Hiding Java interop everywhere Import only classes that clarify call sites
Ignoring qualified keywords Use them when map keys cross namespace boundaries

Practice

  1. Rewrite a namespace that uses use into :require with an alias.
  2. Convert a Java import section into a Clojure ns form with :import.
  3. Decide whether a helper should be called as money/format-cents or referred unqualified.
  4. Create a map with qualified keys and explain what the qualifier communicates.

Key Takeaways

  • Namespaces organize symbols, Vars, classes, and qualified data names.
  • Prefer :require with :as for production code.
  • Use :refer narrowly, especially for test vocabulary or DSL-like contexts.
  • Use :import only for Java classes.
  • A clean ns form makes the rest of the file easier to scan.

Quiz: Namespaces and Requires

### What is the normal top-level form for declaring a Clojure namespace? - [x] `ns` - [ ] `package` - [ ] `class` - [ ] `module` > **Explanation:** The `ns` form establishes the current namespace and usually declares requires and imports. ### What is the safest default for requiring another Clojure namespace? - [x] Use `:require` with `:as`. - [ ] Use `:import`. - [ ] Use `use` for every dependency. - [ ] Copy functions into the current file. > **Explanation:** `:require` with `:as` keeps dependency origins visible at the call site. ### What is `:import` for? - [x] Java classes. - [ ] Clojure namespaces. - [ ] Function arguments. - [ ] Markdown links. > **Explanation:** Clojure namespaces are loaded with `:require`; Java classes are brought in with `:import`. ### Why should `:refer` be used selectively? - [x] It can hide where important names come from. - [ ] It prevents functions from running. - [ ] It only works in Java code. - [ ] It disables the REPL. > **Explanation:** Unqualified referred names can improve readability in small doses, but too many make origins hard to see. ### True or False: `:as-alias` can be useful for qualified keywords even when no Vars are loaded. - [x] True - [ ] False > **Explanation:** `:as-alias` creates an alias for qualification, which is useful for namespaced data keys.
Revised on Saturday, May 23, 2026