Browse Clojure Foundations for Java Developers

Namespaces

What namespaces do in Clojure, how they differ from Java packages, and how to organize code without creating naming conflicts.

A namespace is the main unit of code organization in Clojure. If you come from Java, the closest comparison is a package, but that comparison is only partial.

A Java package mainly groups classes. A Clojure namespace groups vars: functions, values, macros, and other definitions. It also controls how code from other namespaces becomes visible.

What a namespace does

A namespace helps you:

  • group related definitions together
  • avoid symbol collisions across libraries and application modules
  • control imports, aliases, and referred symbols
  • make code navigation easier in the REPL and in editors

In practice, a namespace is both an organizational boundary and a loading boundary.

The basic shape

Most namespaces start with an ns form.

1(ns myapp.orders
2  (:require [clojure.string :as str]
3            [myapp.money :as money]))

This does several jobs at once:

  • declares the current namespace as myapp.orders
  • requires other namespaces
  • gives them aliases so their vars can be used clearly

Later in the file, you might write:

1(defn order-label [order]
2  (str/upper-case (:id order)))

The str/upper-case call is explicit about where the function comes from. That explicitness is usually a good thing.

How this differs from Java packages

Java packages and imports are mostly about class organization. In Clojure, namespaces matter more during active development because you are constantly loading code, evaluating forms, switching REPL context, and choosing which vars to expose.

That means a namespace is not just a folder label. It is part of the running development model.

For a Java developer, a better analogy is:

  • a package for organization
  • imports for visibility
  • plus a bit of module-loading behavior tied into the REPL

Prefer require with aliases

The common default is to use :require and alias other namespaces.

1(ns myapp.reports
2  (:require [clojure.set :as set]
3            [myapp.db :as db]))

That gives you code that stays readable as the project grows.

1(set/union a b)
2(db/load-report id)

For Java engineers, this is roughly equivalent to preferring explicit imports and qualified usage where clarity matters.

Be careful with :refer

You can also bring selected vars directly into scope.

1(ns myapp.math
2  (:require [clojure.string :refer [join split]]))

That can be fine for a small number of very common functions, but overusing :refer makes larger namespaces harder to read because it becomes less obvious where names come from.

A good rule is:

  • alias namespaces by default
  • refer a few symbols only when it clearly improves readability
  • avoid making large files depend on many unqualified external names

Namespaces are also a design signal

If a namespace feels confused, the problem is often not just naming. It may mean the code is doing too many jobs.

A strong namespace usually has:

  • one main responsibility
  • related functions that work on the same part of the domain
  • a dependency list that still feels understandable

When a namespace grows messy, that is often the Clojure version of a Java package or service class that has become too broad.

Common beginner mistakes

Treating a namespace like a Java class

A namespace is not a class. It is a container for related definitions. Do not force class-like structure into it.

Referring too much

Pulling many external symbols directly into scope can make code harder to trace. Prefer clear aliases.

Ignoring reload behavior

In REPL-driven work, loading and reloading namespaces matters. If your namespace has side effects at load time, development can become confusing quickly.

A practical review question

When you read a namespace, ask:

  • what responsibility does this file own?
  • are external dependencies obvious?
  • can I tell where important functions come from?

If yes, the namespace is probably doing its job well.

Knowledge Check

### What is the closest useful Java analogy for a Clojure namespace? - [x] It is partly like a package, but it also controls visibility and loading in a REPL-driven workflow - [ ] It is exactly the same as a Java class - [ ] It is only a folder name with no runtime significance - [ ] It is mainly a build-file concept > **Explanation:** A namespace organizes definitions like a package does, but it also participates directly in how code is loaded and used during interactive development. ### What is usually the best default way to use another namespace in application code? - [x] Require it with an alias and call functions through that alias - [ ] Refer every public symbol into the current namespace - [ ] Copy the functions into the file - [ ] Avoid using multiple namespaces at all > **Explanation:** Aliases keep dependencies explicit and make larger codebases easier to read and navigate. ### What can a messy namespace structure suggest? - [x] The code may be taking on too many responsibilities - [ ] The project should stop using the REPL - [ ] Clojure requires longer file names - [ ] Every function should become a macro > **Explanation:** Namespace quality is often a design signal. If one namespace feels overloaded, the underlying design may need clearer boundaries.
Revised on Friday, April 24, 2026