An excerpt from the repository, fetched Nov 13, 2026.
Read the project’s introduction
edn
extensible data notation [eed-n]
Rationale
edn is an extensible data notation. A superset of edn is used by Clojure to represent
programs, and it is used by Datomic and other applications as a data transfer format. This spec
describes edn in isolation from those and other specific use cases, to help facilitate
implementation of readers and writers in other languages, and for other uses.
edn supports a rich set of built-in elements, and the definition of extension elements in terms
of the others. Users of data formats without such facilities must rely on either convention or
context to convey elements not included in the base set. This greatly complicates application
logic, betraying the apparent simplicity of the format. edn is simple, yet powerful enough to
meet the demands of applications without convention or complex context-sensitive logic.
edn is a system for the conveyance of values. It is not a type system, and has no schemas.
Nor is it a system for representing objects - there are no reference types, nor should a consumer
have an expectation that two equivalent elements in some body of edn will yield distinct object
identities when read, unless a reader implementation goes out of its way to make such a promise.
Thus the resulting values should be considered immutable, and a reader implementation should yield
values that ensure this, to the extent possible.
edn is a set of definitions for acceptable elements. A use of edn might be a stream or
file containing elements, but it could be as small as the conveyance of a single element in e.g. an
HTTP query param.
There is no enclosing element at the top level. Thus edn is suitable for streaming and
interactive applications.
The base set of elements in edn is meant to cover the basic set of data structures common to
most programming languages. While edn specifies how those elements are formatted in text, it
does not dictate the representation that results on the consumer side. A well behaved reader
library should endeavor to map the elements to programming language types with similar semantics.
Spec
Currently this specification is casual, as we gather feedback from implementors. A more rigorous
e.g. BNF will follow.
General considerations
edn elements, streams and files should be encoded using UTF-8.
Elements are generally separated by whitespace. Whitespace, other than within strings, is not
otherwise significant, nor need redundant whitespace be preserved during transmissions. Commas ,
are also considered whitespace, other than within strings.
The delimiters { } ( ) [ ] need not be separated from adjacent elements by whitespace.
# dispatch character
Tokens beginning with # are reserved. The character following # determines the behavior. The
dispatches #{ (sets), #_ (discard), #alphabetic-char (tag) are defined below. # is not a
delimiter.
Built-in elements
nil
nil represents nil, null or nothing. It should be read as an object with similar meaning on the
target platform.
booleans
true and false should be mapped to booleans.
If a platform has canonic values for true and false, it is a further semantic of booleans that all
instances of true yield that (identical) value, and similarly for false.
strings
Strings are enclosed in "double quotes". May span multiple lines. Standard C/Java escape
characters \t, \r, \n, \\ and \" are supported.
characters
Characters are preceded by a backslash: \c, \newline, \return, \space and \tab yield the
corresponding characters. Unicode characters are represented with \uNNNN as in Java. Backslash cannot be
followed by whitespace.
symbols
Symbols are used to represent identifiers, and should map to something other than strings, if
possible.
Symbols begin with a non-numeric character and can contain alphanumeric characters and . * + ! - _ ? $ % & = < >. If -, + or . are the first character, the second character (if any) must be
non-numeric. Additionally, : # are allowed as constituent characters in symbols other than as the
first character.
/ has special meaning in symbols. It can be used once only in the middle of a symbol to separate
the prefix (often a namespace) from the name, e.g. my-namespace/foo. / by itself is a legal
symbol, but otherwise neither the prefix nor the name part can be empty when the symbol
contains /.
If a symbol has a prefix and /, the following name component should follow the
first-character restrictions for symbols as a whole. This is to avoid ambiguity in reading contexts
where prefixes might be presumed as implicitly included namespaces and elided thereafter.
keywords
Keywords are identifiers that typically designate themselves. They are semantically akin to
enumeration values. Keywords follow the rules of symbols, except they can (and must) begin with :, e.g. :fred or :my/fred. If the target platform does not have a keyword type distinct
from a symbol type, the same type can be used without conflict, since the mandatory leading : of
keywords is disallowed for symbols. Per the symbol rules above, :/ and :/anything are not legal keywords.
A keyword cannot begin with ::
If the target platform supports some notion of interning, it is a further semantic of keywords that
all instances of the same keyword yield the identical object.
integers
Integers consist of the digits 0 - 9, optionally prefixed by - to indicate a negative number, or
(redundantly) by +. No integer other than 0 may begin with 0. 64-bit (signed integer) precision is
expected. An integer can have the suffix N to indicate that arbitrary precision is desired. -0 is a
valid integer not distinct from 0.
integer
int
int N
digit
0-9
int
digit
1-9 digits
+ digit
+ 1-9 digits
- digit
- 1-9 digits
floating point numbers
64-bit (double) precision is expected.
floating-point-number
int M
int frac
int exp
int frac exp
digit
0-9
int
digit
1-9 digits
+ digit
+ 1-9 digits
- digit
- 1-9 digits
frac
. digits
exp
ex digits
digits
digit
digit digits
ex
e
e+
e-
E
E+
E-
In
Read the full README on GitHub