> For the complete documentation index, see [llms.txt](https://deeplearning4j.konduit.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://deeplearning4j.konduit.ai/en-1.0.0-rewrite/nd4j/serialization.md).

# Serialization

### Serialization

ND4J provides several serialization formats for `INDArray` instances. Choosing the right one depends on your priorities: raw throughput, human-readable output, or interoperability with Python/NumPy pipelines.

| Format                     | Write                      | Read                     | Best for                 |
| -------------------------- | -------------------------- | ------------------------ | ------------------------ |
| Binary (`Nd4j`)            | `Nd4j.write`               | `Nd4j.read`              | Fast file persistence    |
| ByteBuffer (`BinarySerde`) | `BinarySerde.toByteBuffer` | `BinarySerde.toArray`    | In-memory / IPC transfer |
| Text                       | `Nd4j.writeTxt`            | `Nd4j.readTxt`           | Debugging, inspection    |
| NumPy text (CSV)           | —                          | `Nd4j.readNumpy`         | Import CSV/NumPy text    |
| NumPy binary (`.npy`)      | —                          | `Nd4j.createFromNpyFile` | Python interoperability  |

***

### 1. Binary Format

The binary format is the most compact and fastest option for disk persistence. It serializes the full array — shape, data type, order, and element values — into a compact byte stream using Java's `DataOutputStream` / `DataInputStream`.

**Write:**

```java
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;

import java.io.*;

INDArray arr = Nd4j.linspace(1, 10, 10).reshape(2, 5);

try (DataOutputStream out = new DataOutputStream(
        new BufferedOutputStream(new FileOutputStream("array.bin")))) {
    Nd4j.write(arr, out);
}
```

**Read:**

```java
INDArray loaded;

try (DataInputStream in = new DataInputStream(
        new BufferedInputStream(new FileInputStream("array.bin")))) {
    loaded = Nd4j.read(in);
}
```

The deserialized array is identical to the original: same shape, same data type, same element ordering. Wrapping the underlying stream in a `BufferedOutputStream` / `BufferedInputStream` is recommended for large arrays to avoid excessive system-call overhead.

**When to use:** File checkpoints between JVM sessions, persisting intermediate computation results, or anywhere you need the smallest on-disk footprint with the fastest read-back time.

***

### 2. ByteBuffer Format

`BinarySerde` serializes an `INDArray` into a `java.nio.ByteBuffer`. When the array's underlying data is already stored in a direct (off-heap) buffer, this conversion can avoid a data copy entirely, making it well-suited for inter-process communication, shared-memory transfers, or handing data off to a native library.

**Maven dependency** — `BinarySerde` lives in the `nd4j-serde` module:

```xml
<dependency>
    <groupId>org.nd4j</groupId>
    <artifactId>nd4j-serde</artifactId>
    <version>${nd4j.version}</version>
</dependency>
```

**Write to ByteBuffer:**

```java
import org.nd4j.serde.binary.BinarySerde;

import java.nio.ByteBuffer;

INDArray arr = Nd4j.rand(3, 4);

// Serialize to a ByteBuffer (direct buffer, zero-copy when possible)
ByteBuffer buffer = BinarySerde.toByteBuffer(arr);
```

**Read from ByteBuffer:**

```java
INDArray recovered = BinarySerde.toArray(buffer);
```

**Writing / reading via a file channel** (useful for memory-mapped files):

```java
import java.nio.channels.FileChannel;
import java.nio.file.*;

Path path = Paths.get("array.buf");

// Write
try (FileChannel ch = FileChannel.open(path,
        StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    BinarySerde.writeArrayToChannel(arr, ch);
}

// Read
try (FileChannel ch = FileChannel.open(path, StandardOpenOption.READ)) {
    INDArray loaded = BinarySerde.readFromChannel(ch);
}
```

**When to use:** In-memory handoffs between components running in the same JVM, native-bridge scenarios, or when using memory-mapped files for very large arrays. The zero-copy property only applies when the array's data buffer is already in a compatible direct-memory layout; otherwise a copy is made transparently.

***

### 3. Text Format

The text format writes each element as a human-readable floating-point number. Rows are delimited by newlines and columns by commas (the exact delimiter is locale-independent).

**Write:**

```java
Nd4j.writeTxt(arr, "array.txt");
```

**Read:**

```java
INDArray loaded = Nd4j.readTxt("array.txt");
```

**Example output** for a 2x3 array:

```
1.000000,2.000000,3.000000
4.000000,5.000000,6.000000
```

Text serialization round-trips correctly for the default float precision, but be aware that the conversion to decimal representation and back introduces a tiny floating-point rounding error. For double-precision arrays where bit-exact round-tripping matters, prefer the binary format.

**When to use:** Spot-checking intermediate values during development, sharing arrays with non-Java tooling that can read CSV, or generating test fixtures that should be human-auditable.

***

### 4. NumPy Text (CSV) Format

`Nd4j.readNumpy` reads a plain-text file whose rows are whitespace- or comma-separated numbers — the same format produced by NumPy's `numpy.savetxt` and by many CSV export tools.

```python
# Python side — generate the file
import numpy as np
a = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
np.savetxt("array.csv", a, delimiter=",")
```

```java
// Java side — read it back
// Second argument is the delimiter used in the file
INDArray arr = Nd4j.readNumpy("array.csv", ",");
```

The result is always a 2D row-major `INDArray`. The delimiter must match exactly what was used during export. Common choices are `","` for CSV and `" "` for space-separated files.

**Note:** `Nd4j.writeNumpy` (which wrote a compatible text file) was deprecated in earlier releases. For writing, use `Nd4j.writeTxt` or the NumPy binary format described below.

**When to use:** Importing datasets or weights that were exported from a Python/NumPy workflow using `numpy.savetxt` or any CSV-producing tool.

***

### 5. NumPy Binary (`.npy`) Format

The `.npy` binary format is the standard serialization format for single NumPy arrays. It stores the array's dtype, shape, byte order, and raw element data in a compact binary file that NumPy can read and write natively.

**Python side — save a `.npy` file:**

```python
import numpy as np
arr = np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float32)
np.save("array.npy", arr)
```

**Java side — load the `.npy` file:**

```java
import java.io.File;

INDArray arr = Nd4j.createFromNpyFile(new File("array.npy"));
```

ND4J reads the header to determine the shape and dtype automatically — no manual configuration is needed. The returned array preserves the original dtype (e.g., `float32` maps to `DataType.FLOAT`, `float64` maps to `DataType.DOUBLE`).

**Saving from Java for NumPy to read:**

```java
// Write a .npy file that Python can load with numpy.load()
Nd4j.writeAsNumpy(arr, new File("output.npy"));
```

```python
# Python side — verify
import numpy as np
a = np.load("output.npy")
print(a.shape, a.dtype)
```

**When to use:** Any time you need to exchange arrays between a Java/DL4J pipeline and a Python/NumPy/PyTorch/TensorFlow pipeline. The `.npy` format is the most reliable interoperability path because it preserves dtype, shape, and byte order without ambiguity.

***

### 6. Additional Serialization Back-ends (nd4j-serde)

The `nd4j-serde` module provides adapters for other serialization ecosystems:

| Sub-module                     | Description                                                                                                                 |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `nd4j-serde/nd4j-jackson`      | Jackson `JsonSerializer` / `JsonDeserializer` for `INDArray` — embeds arrays as Base64-encoded binary inside JSON documents |
| `nd4j-serde/nd4j-kryo`         | Kryo serializer for `INDArray` — useful in Apache Spark or other distributed frameworks that use Kryo as their wire format  |
| `nd4j-serde/nd4j-aeron`        | Aeron-compatible serialization for low-latency messaging                                                                    |
| `nd4j-serde/nd4j-camel-routes` | Apache Camel data-format adapter                                                                                            |

The Jackson integration is particularly common when embedding arrays in REST API payloads:

```java
import org.nd4j.serde.jackson.ndarray.NDArrayDeSerializer;
import org.nd4j.serde.jackson.ndarray.NDArraySerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(INDArray.class, new NDArraySerializer());
module.addDeserializer(INDArray.class, new NDArrayDeSerializer());
mapper.registerModule(module);

// Serialize to JSON string
String json = mapper.writeValueAsString(arr);

// Deserialize back
INDArray loaded = mapper.readValue(json, INDArray.class);
```

***

### Choosing a Format

**Use binary (`Nd4j.write` / `Nd4j.read`) when:**

* You need maximum speed and minimum file size for JVM-to-JVM persistence.
* You are checkpointing intermediate results in a training loop.
* Portability outside the JVM is not required.

**Use `BinarySerde` when:**

* You are passing arrays between threads or processes within the same machine.
* You want zero-copy semantics or need to work with memory-mapped files.
* You are integrating with a native library through a `ByteBuffer` API.

**Use text (`Nd4j.writeTxt` / `Nd4j.readTxt`) when:**

* You want to visually inspect values in a text editor or log file.
* You are writing test fixtures that need to be human-readable and diffable.
* Absolute bit-exact round-tripping is not required.

**Use NumPy text (`Nd4j.readNumpy`) when:**

* You are importing data that was exported by `numpy.savetxt` or another CSV tool.
* The producing system cannot write `.npy` binary files.

**Use NumPy binary (`Nd4j.createFromNpyFile` / `Nd4j.writeAsNumpy`) when:**

* You are integrating with a Python-based ecosystem (NumPy, pandas, PyTorch, TensorFlow).
* You need dtype and shape metadata to be preserved automatically.
* You want the most portable and widely supported binary array format available.

***

### Complete Example

The following snippet demonstrates all formats in a single class:

```java
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.serde.binary.BinarySerde;

import java.io.*;
import java.nio.ByteBuffer;

public class SerializationDemo {

    public static void main(String[] args) throws Exception {

        INDArray original = Nd4j.linspace(1, 12, 12).reshape(3, 4);
        System.out.println("Original:\n" + original);

        // ---- 1. Binary (DataStream) ----
        try (DataOutputStream dos = new DataOutputStream(
                new FileOutputStream("array.bin"))) {
            Nd4j.write(original, dos);
        }
        INDArray fromBin;
        try (DataInputStream dis = new DataInputStream(
                new FileInputStream("array.bin"))) {
            fromBin = Nd4j.read(dis);
        }
        System.out.println("From binary file:\n" + fromBin);

        // ---- 2. ByteBuffer ----
        ByteBuffer buf = BinarySerde.toByteBuffer(original);
        INDArray fromBuf = BinarySerde.toArray(buf);
        System.out.println("From ByteBuffer:\n" + fromBuf);

        // ---- 3. Text ----
        Nd4j.writeTxt(original, "array.txt");
        INDArray fromTxt = Nd4j.readTxt("array.txt");
        System.out.println("From text file:\n" + fromTxt);

        // ---- 4. NumPy text (read only; file produced externally) ----
        // INDArray fromCsv = Nd4j.readNumpy("array.csv", ",");

        // ---- 5. NumPy binary ----
        Nd4j.writeAsNumpy(original, new File("array.npy"));
        INDArray fromNpy = Nd4j.createFromNpyFile(new File("array.npy"));
        System.out.println("From .npy file:\n" + fromNpy);
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://deeplearning4j.konduit.ai/en-1.0.0-rewrite/nd4j/serialization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
