Skip to content
Logo of XTDB

XTDB 2.x Early Access

XTDB is a bitemporal and dynamic relational database for SQL and Datalog.

XTDB 2.x is still work-in-progress and currently unreleased software (alpha release coming soon!). Current documentation:

Want to try it quickly right now?

Scroll down to find out how below!

About 2.x Early Access

This 2.x Early Access programme provides visibility for users who are interested in the broad future of XTDB. Developing in the open allows us to process feedback faster and deliver on our promises sooner. This also means that many things we intend to implement or fix prior to General Availability (or even an alpha release) will currently produce opaque error messages, undocumented bugs, and a generally unreliable experience. Please be forgiving!

XTDB 1.x will remain supported for the foreseeable future - we will continue to triage 1.x issues and provide releases well beyond 2.x General Availability.

Early Access will continue until we are satisfied that the performance and deployment of 2.x is robust enough to recommend for production usage. This will require closely collaborating with partners and users who are prepared to test and give feedback on our bleeding edge changes. Interested to help? Get in touch!

Key Features of XTDB 2.x

  • Cloud native: modern columnar architecture built around Apache Arrow and commodity object storage.
  • Bitemporal: all data is accurately versioned as updates are made (system time), and all data exists within a universal domain timeline for representing 'validity'/'effectivity' (valid time).
  • Dynamic: no upfront schema needs to be specified before records can be inserted. Complex and nested data is automatically represented using Apache Arrow types.
  • Relational: the full spectrum of traditional SQL database capabilities is available - including joins, transactions, bag/multiset semantics, three-valued logic, multiple N-ary relations etc.
  • SQL: unrestricted accessibility for a mainstream audience and an eye to the future with preliminary Flight SQL driver support.
  • Datalog: programmer-friendly API for complex relational querying that overcomes many of SQL’s compositional challenges.

Check out our detailed What is XTDB breakdown to learn more about what makes XTDB special. ✨

Things you can try right now:

Feel free to mix and match the SQL and Datalog snippets - they're interoperable!

If you have any issues with these specific examples, please let us know:


Via Docker or as a JVM library

;; deps.edn
{:mvn/repos {"ossrh-snapshots" {:url ""}}
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}
        com.xtdb.labs/xtdb-api {:mvn/version "2.0.0-SNAPSHOT"}
        com.xtdb.labs/xtdb-core {:mvn/version "2.0.0-SNAPSHOT"}
        com.xtdb.labs/xtdb-http-server {:mvn/version "2.0.0-SNAPSHOT"}
        com.xtdb.labs/xtdb-pgwire-server {:mvn/version "2.0.0-SNAPSHOT"}}
 {:xtdb {:jvm-opts
          ;; needed on JDK16+
  ;; If you want to connect using nREPL
  {:main-opts ["-m" "nrepl.cmdline"]
   :extra-deps {nrepl/nrepl {:mvn/version "1.0.0"}}}}}

;; Once you have a REPL (started with clj -A:xtdb -M:nrepl if you’re on JDK 16+), you can create an in-memory XTDB node with:
(require '[xtdb.node :as xt.node]
         '[xtdb.api :as xt])

(def my-node (xt.node/start-node {:xtdb/server {:port 3001}
                                  :xtdb/pgwire {:port 5432}}))

;; Confirm this API call returns successfully
(xt/status my-node)


Via either (1) HTTP Clojure client driver, (2) experimental SQL-only pgwire-server compatibility, or (3) use the embedded node started via your Clojure REPL (i.e. skip this step)

;; deps.edn
{:mvn/repos {"ossrh-snapshots" {:url ""}}
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}
        com.xtdb.labs/xtdb-api {:mvn/version "2.0.0-SNAPSHOT"}
        com.xtdb.labs/xtdb-http-client-clj {:mvn/version "2.0.0-SNAPSHOT"}}}

;; Once you have a repl started ...
(require '[xtdb.client :as xt.client]
         '[xtdb.api :as xt])

(def my-node (xt.client/start-client "http://localhost:3001"))

(xt/status my-node)

Instant Schemaless Writes

XTDB does not require any pre-defined schema or tables. Every insert, update, and delete is immutable.

(xt/submit-tx my-node [[:put :posts {:xt/id 1234
                                     :user-id 5678
                                     :text "hello world!"}]])

(xt/q my-node '{:find [text]
                :where [($ :posts [text])]})

First-Class Nested Data

Relational querying for messy data.

;; XTDB has always handled ~arbitrary data well - just smash your maps in!
(xt/submit-tx my-node [[:put :people {:xt/id 5678
                                      :name "Sarah"
                                      :friends [{:user "Dan"}
                                                {:user "Kath"}]}]])

;; Datalog now supports first-class nested lookups too:
(xt/q my-node '{:find [friend]
                :where [($ :people [friends])
                        [(nth friends 1) friend]]})

Native Bitemporality

No more maintaining your own timestamp columns for soft-delete, versioning or audit requirements.

;; Datalog uses as-of-now defaults
;; To view the entire history of a record:
(xt/q my-node '{:find [person
                       valid-from valid-to
                       system-from system-to]
                :where [($ :people [{:xt/id 5678
                                     :xt/* person
                                     :xt/valid-from valid-from
                                     :xt/valid-to valid-to
                                     :xt/system-from system-from
                                     :xt/system-to system-to}]
                                   {:for-valid-time :all-time
                                    :for-system-time :all-time})]})

Cross-Time Queries

Time in XTDB is optional – but universal. Advanced applications can even query time itself.

(xt/submit-tx my-node [[:put :posts
                             {:xt/id 9012 ;; original post
                              :user-id 5678
                              :text "Happy 2019!"}
                               [:in #inst "2019-01-01" nil]}]
                       [:put :posts
                             {:xt/id 3456 ;; later post
                              :user-id 5678
                              :text "(New) Happy 2024!"}
                               [:in #inst "2024-01-01" nil]}]
                       [:put :posts
                             {:xt/id 9012 ;; original post again
                              :user-id 5678
                              :text "Edited-2019-post: Happy 2025!"}
                               [:in #inst "2025-01-01" nil]}]])

(xt/q my-node '{:find [text]
                :where [($ :posts [text]
                                   [:at #inst "2025-01-02"]})]})

(xt/q my-node '{:find [text]
                :where [($ :posts [text])]})

;; what other (versions of) posts were valid during the same time range as the 2019 post?
(xt/q my-node '{:find [text]
                :where [($ :posts [{:xt/id 3456
                                    :xt/valid-time vt}]
                                  {:for-valid-time :all-time})
                        ($ :posts [{:xt/id other-id
                                    :xt/valid-time other-vt} text]
                                   {:for-valid-time :all-time})
                        [(<> other-id 3456)]
                        [(overlaps? vt other-vt)]]})

Native Apache Arrow

XTDB embraces Apache Arrow both internally and externally.

SELECT more_posts.text
  AS more_posts;

Complete Erasure

To comply with privacy laws, erasure is necessary when handling immutable data.

;; we are going to rename :evict to :erase in the near future
(xt/submit-tx my-node [[:evict :people 5678]])

What next?

Why not Learn Datalog Today! Or generate your own playground starter project using our Clojure templates!

New for 1.x users

The 2.x design expands on the essential qualities of 1.x and provides significant new capabilities:

The roadmap towards General Availability

This roadmap is an expression of intent and is subject to change.

XTDB Cloud Service?

Are you eagerly waiting for our announcement of v2.x as a usage-based cloud service? Join the waiting list here.

Want to chat?

Get in touch!