What Is a Namespace?
In Clojure, a namespace is a first-class, named mapping from symbols to vars. Almost every source file declares exactly one namespace, and that namespace becomes the container for all the functions and values defined in the file, so nothing you define ever silently collides with something of the same name defined elsewhere.
Cricket analogy: Just as the IPL keeps every team's squad list in its own franchise ledger so 'Kohli' unambiguously means Royal Challengers Bangalore's Kohli and not someone else's, a Clojure namespace like myapp.core keeps its own symbol-to-var table so 'process' in myapp.core never collides with 'process' in myapp.utils.
Declaring a Namespace with ns
The ns macro at the top of a file declares the namespace's name and its dependencies in one place. Inside it, :require brings in other Clojure namespaces (typically aliased with :as so their vars can be referenced concisely), and :import brings in Java classes so they can be used by their short name instead of a fully qualified one.
Cricket analogy: Selecting a playing XI means naming which players you're bringing in for the match and giving some a shorter nickname on the scoreboard, rather than listing every player's full legal name every single time the scoreboard updates.
(ns myapp.core
(:require [clojure.string :as str]
[myapp.db :as db]
[myapp.utils.parser :refer [parse-line]])
(:import (java.util Date)
(java.text SimpleDateFormat)))
(defn- format-now []
(let [fmt (SimpleDateFormat. "yyyy-MM-dd")]
(.format fmt (Date.))))
(defn greet [name]
(str/join " " ["Hello," (str/capitalize name) (format-now)]))
;; At the REPL, after editing myapp.db, reload it without restarting:
(require '[myapp.db :as db] :reload)
require vs use, and Reloading at the REPL
The older (use 'ns) form, and the :refer :all option on :require, pull every public var from a namespace into scope unqualified. This is convenient for quick scripts but risky in application code: it hides where a symbol actually came from and can silently shadow an existing var. Preferring :as aliasing, or a narrow :refer [specific-fn], keeps every reference traceable back to its source namespace.
Cricket analogy: Calling in every reserve player from the whole domestic circuit onto the field creates chaos about who's actually fielding where, whereas naming only the specific all-rounder you need keeps the playing XI unambiguous.
Prefer :require with :as aliasing over :use / :refer :all in application code — it keeps the origin of every symbol traceable and avoids silent name collisions when two required namespaces happen to define a var with the same name.
Qualified Symbols and Private Vars
Any var can be referenced by its fully qualified name, namespace/symbol, which is unambiguous no matter what's currently required in the calling namespace. defn- (shorthand for defn plus ^:private metadata) creates a var that's visible only within its own namespace, giving you a simple way to hide implementation details from the rest of the codebase.
Cricket analogy: Announcing a substitute as 'Mumbai Indians' Suryakumar Yadav' rather than just 'Suryakumar' avoids confusion with any other SKY in the league, the same way a fully qualified symbol is never mistaken for another namespace's function; a team's internal fitness data stays in the dressing room.
Circular requires — namespace A requiring B while B requires A — will throw a compile-time error. If two namespaces seem to need each other, extract the shared functions into a third namespace that both can require, or restructure so the dependency flows in one direction only.
- A namespace is a first-class mapping from symbols to vars, typically one per source file.
- File paths mirror namespace names, with dashes in the namespace converted to underscores in the file name (myapp.utils.parser to myapp/utils/parser.clj).
- The ns macro at the top of a file declares :require for other Clojure namespaces and :import for Java classes.
- Use :as to alias a namespace and :refer [sym1 sym2] to pull in only specific named symbols.
- Avoid :refer :all / (use ...) in application code; it silently pollutes the namespace and hides where a symbol came from.
- defn- creates a private var that's only accessible within its own namespace.
- Circular requires between two namespaces are a compile error — break the cycle by extracting shared code into a third namespace.
Practice what you learned
1. What does the :as key inside a :require clause do?
2. Which form is generally discouraged in application code because it can silently cause naming collisions?
3. How does a Clojure namespace name like myapp.utils.parser typically map to a file path?
4. What does defn- do differently from defn?
5. What happens if namespace A requires namespace B, and B also requires A?
Was this page helpful?
You May Also Like
Leiningen and deps.edn
Compare Clojure's two main build tools — Leiningen's project.clj and the official tools.deps CLI's deps.edn — and learn how each manages dependencies, profiles, and aliases.
Clojure and Java Interop
Understand how Clojure calls Java classes and methods directly via dot notation, implements interfaces with proxy/reify/gen-class, and handles exceptions and type hints for performance.
Testing with clojure.test
Learn Clojure's built-in testing framework — deftest, is, are, fixtures, and how to organize and selectively run tests in a real project.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics