diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 316909cb207b23926981d903e2696da343a050f1..21cc8bd1e39ede5588f11be9e9a8759f98eacd4d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,9 +1,25 @@
+variables:
+  CAISAR_VERSION: "0.2.0"
+
 stages:
+  - build
   - test
+  - doc
   - make_public
 
-tests:
-  stage: test
+build:
+  stage: build
+  script:
+    - nix --extra-experimental-features "nix-command flakes" build
+    - nix --extra-experimental-features "nix-command flakes" flake check
+  tags:
+    - nix-v2
+  when: always
+  interruptible: true
+
+# Optional and manual full rebuild using a clean docker image
+full_rebuild_and_test:
+  stage: build
   image: ocaml/opam@sha256:013a26ccbaa8344b63274e335e2492c432cec1c3526b9ba888ab151abb2b4c25
   cache:
     key: $CI_COMMIT_REF_SLUG
@@ -23,22 +39,30 @@ tests:
     - make test-ci
   tags:
     - docker
+  when: manual
+  interruptible: true
+
+test:
+  stage: test
+  script:
+    - nix --extra-experimental-features "nix-command flakes" flake check
+  tags:
+    - nix-v2
   when: always
   interruptible: true
 
 ## Manual generation of the documentation
 
 documentation:
-  stage: test
-  image: sphinxdoc/sphinx-latexpdf@sha256:f80e48ac46a14736795e561e79a2fa43835a5aaa2cfa4bdc6021d85d329da5f2
+  stage: doc
   script:
-    - make doc
+    - nix --extra-experimental-features "nix-command flakes" build
   artifacts:
    paths:
-     - doc/_build/html/
-     - doc/_build/latex/
+     - result/share/doc/ocaml4.14.1-caisar-${CAISAR_VERSION}/html
+     - result/share/doc/ocaml4.14.1-caisar-${CAISAR_VERSION}/latex
   tags:
-    - docker
+    - nix-v2
   when: manual
   interruptible: true
 
diff --git a/README.md b/README.md
index 47547832b3cfaed07d528811a6ccd1af28fff198..4b7c5fc9529f3432166843260789b6e6a48cada1 100644
--- a/README.md
+++ b/README.md
@@ -49,9 +49,31 @@ To run the CAISAR [Docker](https://www.docker.com/) image, do the following:
 docker run -it laiser/caisar:pub sh
 ```
 
+### Nix flake
+A CAISAR Nix flake allow for reproducible build, and setting up a development
+environment. It requires Nix version 2.15 or higher as well as enabling flakes.
+Please refer to the official Nix [documentation](https://nixos.wiki/wiki/Flakes#Temporary) to enable Nix flakes.
+
+Assuming you have Nix installed and are at the CAISAR repository root, you can
+build CAISAR using the following command:
+
+```
+nix build
+```
+
+You can setup a development environment with all CAISAR dependencies
+included using [nix develop](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html).
+It will contain the ocaml toolchain already setup and installed,
+and the ocaml language server and formatter. You can thus compile and test
+CAISAR in an isolated shell using the following command:
+
+```
+nix develop
+```
+
 ### From source code
 
-**Please note:** CAISAR requires the OCaml package manager [opam](https://opam.ocaml.org/),
+**Please note:** building CAISAR from source requires the OCaml package manager [opam](https://opam.ocaml.org/),
 v2.1 or higher, which is typically avaible in all major GNU/Linux distributions.
 
 To build and install CAISAR, do the following:
diff --git a/doc/installation.rst b/doc/installation.rst
index b5df738d5b3deb10e76fe34afed02056dd462c5d..62199f954fef870d5739735ae668254ee4b7b3ae 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -53,6 +53,54 @@ To run the CAISAR Docker image, do the following:
 
    $ docker run -it laiser/caisar:pub sh
 
+Install through Nix
+-------------------
+
+This method requires Nix (version 2.15 or above) to be installed on your system.
+
+From Nixpkgs
+************
+
+CAISAR is currently not directly available on Nixpkgs. This should change for
+the future release.
+
+Using Nix flake
+***************
+
+A CAISAR `flake <https://nixos.wiki/wiki/Flakes>`_ is available at the root of
+CAISAR directory. At the time of writing, flakes are still considered
+experimental by NixOS. Hence, to use it, you will need to enable them following
+the official Nix `instructions <https://nixos.wiki/wiki/Flakes#Temporary>`_.
+
+Assuming you have Nix installed and are at the CAISAR repository root, you can
+build CAISAR using the following command:
+
+.. code-block:: console
+
+   $ nix build
+
+.. warning ::
+   This command will fetch the Nixpkg registry for all build dependencies.
+   This will result in several megabytes download. Make sure you have
+   a stable network connexion before attempting building through Nix.
+
+The CAISAR binary will reside in ``result/bin/caisar``. The manual will be under ``result/share/doc/ocaml4.14.1-caisar-0.2.0/``.
+
+You can run the CAISAR test suite using the following command:
+
+.. code-block:: console
+
+   $ nix flake check
+
+You can setup a development environment with all CAISAR dependencies included using
+`nix develop
+<https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html>`_.
+It will contain the ocaml toolchain already setup and installed, and the ocaml language server and formatter. You can thus compile and test CAISAR in an isolated shell.
+
+.. code-block :: console
+
+   $ nix develop
+
 Compile from source
 -------------------
 
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000000000000000000000000000000000000..dcc1c4d006bea0576d46645316b481a433d79db3
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,77 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1694529238,
+        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nix-filter": {
+      "locked": {
+        "lastModified": 1694857738,
+        "narHash": "sha256-bxxNyLHjhu0N8T3REINXQ2ZkJco0ABFPn6PIe2QUfqo=",
+        "owner": "numtide",
+        "repo": "nix-filter",
+        "rev": "41fd48e00c22b4ced525af521ead8792402de0ea",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "nix-filter",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1694948089,
+        "narHash": "sha256-d2B282GmQ9o8klc22/Rbbbj6r99EnELQpOQjWMyv0rU=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "5148520bfab61f99fd25fb9ff7bfbb50dad3c9db",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "5148520bfab61f99fd25fb9ff7bfbb50dad3c9db",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "nix-filter": "nix-filter",
+        "nixpkgs": "nixpkgs"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000000000000000000000000000000000000..01d199d6b2214ce7547792a2937160ea28a62683
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,110 @@
+{
+  description = "CAISAR Nix flake.";
+  inputs = {
+    flake-utils.url = "github:numtide/flake-utils";
+    nix-filter.url = "github:numtide/nix-filter";
+    nixpkgs.url = github:NixOS/nixpkgs/5148520bfab61f99fd25fb9ff7bfbb50dad3c9db;
+  };
+  outputs =
+    { self
+    , flake-utils
+    , nixpkgs
+    , nix-filter
+    , ...
+    }:
+    flake-utils.lib.eachDefaultSystem (system:
+    let
+      pkgs = nixpkgs.legacyPackages.${system};
+      ocamlPkgs = pkgs.ocaml-ng.ocamlPackages_4_14;
+      lib = pkgs.lib;
+      sources = {
+        ocaml = nix-filter.lib {
+          root = ./.;
+          include = [
+            ".ocamlformat"
+            "dune-project"
+            "Makefile"
+            (nix-filter.lib.inDirectory "src")
+            (nix-filter.lib.inDirectory "lib")
+            (nix-filter.lib.inDirectory "test")
+            (nix-filter.lib.inDirectory "doc")
+          ];
+        };
+      };
+    in
+    rec {
+      packages = rec {
+        default = self.packages.${system}.caisar;
+        # CAISAR package; includes binary and documentation
+        caisar = ocamlPkgs.buildDunePackage
+          {
+            pname = "caisar";
+            version = "0.2.0";
+            duneVersion = "3";
+            minimalOCamlVersion = "4.13";
+            installTargets = "all doc";
+            src = sources.ocaml;
+            nativeBuildInputs = [
+              ocamlPkgs.ocaml-protoc-plugin
+              pkgs.protobuf
+              # For documentation
+              pkgs.sphinxHook
+            ];
+            sphinxBuilders = [
+              "html"
+              "latex"
+              # TODO: generate pdf automatically
+            ];
+            buildInputs = with ocamlPkgs;
+              [
+                csv
+                ocplib-endian
+                zarith
+                ocamlgraph
+                ppx_deriving
+                ppx_deriving_yojson
+                ppx_inline_test
+                ocaml-protoc-plugin
+                re
+                fpath
+                dune-site
+                fmt
+                logs
+                cmdliner
+                yaml
+                pkgs.why3
+              ];
+          };
+      };
+
+      checks = {
+        default =
+          self.packages.${system}.default.overrideAttrs
+            (oldAttrs: {
+              name = "check-${oldAttrs.name}";
+              dontBuild = true;
+              dontInstall = true;
+              doCheck = true;
+              checkPhase = "make test-ci";
+            });
+      };
+      apps = rec {
+        default = {
+          type = "app";
+          program =
+            "${self.packages.${system}.default}/bin/caisar";
+        };
+      };
+      devShells = rec {
+        default = pkgs.mkShell {
+          name = "CAISAR development shell environment.";
+          inputsFrom = [ self.packages.${system}.caisar ];
+          packages = with ocamlPkgs; [ ocamlformat_0_25_1 ocaml-lsp ];
+          shellHook = ''
+            echo "Welcome in the development shell for CAISAR."
+          '';
+        };
+      };
+    });
+}
+