# How to Use ArrayProperty in Neomodel for Storing Lists of Values

> Learn how to use Neomodel ArrayProperty to store lists of values in Neo4j. This guide covers scalar values, typed objects, indexing, and validation for efficient data management.

- Repository: [Neo4j Contrib/neomodel](https://github.com/neo4j-contrib/neomodel)
- Tags: how-to-guide
- Published: 2026-03-08

---

**`ArrayProperty` is Neomodel's wrapper for Neo4j's native list type, enabling models to store ordered collections of scalar values or typed objects with optional indexing and validation.**

In the `neo4j-contrib/neomodel` library, `ArrayProperty` provides the primary mechanism for persisting Python lists as Neo4j array properties. Defined in [`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py) (lines 336-386), this property class handles automatic serialization between Python lists and Neo4j's native array type while supporting type-safe collections through its `base_property` parameter.

## Core Implementation of ArrayProperty

### Class Architecture and Data Translation

The `ArrayProperty` class inherits from the base `Property` class and implements custom `inflate` and `deflate` methods to manage bidirectional translation between Python lists and Neo4j arrays. When a node is saved, the `deflate` method converts the Python list to a format Neo4j can store; upon retrieval, `inflate` reconstructs the Python list from the database array.

### The base_property Parameter for Type Safety

The optional `base_property` parameter enables element-level validation by processing each list item through another Property instance's conversion methods:

```python
from neomodel import StructuredNode, StringProperty, ArrayProperty, IntegerProperty

class Score(StructuredNode):
    player = StringProperty()
    points = ArrayProperty(IntegerProperty())  # Enforces integer elements only

```

When `base_property` is provided, each element passes through that property's `inflate` and `deflate` methods, raising `DeflateError` if type conversion fails (as implemented in lines 340-378 of [`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py)).

## Basic Usage Patterns

### Storing Untyped Arrays

For flexible storage of heterogeneous data, instantiate `ArrayProperty` without a base type:

```python
class Person(StructuredNode):
    name = StringProperty(required=True)
    tags = ArrayProperty()  # Accepts any Neo4j-compatible values

# Create and persist

person = Person(name="Alice", tags=["friend", "colleague", "admin"]).save()

# Retrieve and verify

retrieved = Person.nodes.get(name="Alice")
assert "friend" in retrieved.tags

```

This pattern corresponds to the test implementation in [`test/sync_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_properties.py) (lines 84-88).

### Validating Typed Arrays

When data integrity is critical, combine `ArrayProperty` with specific property types:

```python

# Valid operation

Score(player="Bob", points=[10, 20, 30]).save()

# Invalid operation raises DeflateError

try:
    Score(player="Bob", points=["ten"]).save()
except DeflateError:
    print("Validation failed: non-integer value in array")

```

The validation logic executes during the save operation, preventing invalid data from reaching the database (verified in [`test/sync_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_properties.py), lines 90-100).

## Indexing and Constraints

### Creating Database Indexes on Arrays

`ArrayProperty` supports Neo4j indexing at the array level, treating the entire list as a single indexed value:

```python
class UniqueArrayNode(StructuredNode):
    values = ArrayProperty(unique_index=True)

```

When `install_labels` executes, this creates a unique constraint on the complete array value. Query performance improves for exact array matches:

```python
node = UniqueArrayNode(values=[1, 2, 3]).save()
result = UniqueArrayNode.nodes.get(values=[1, 2, 3])  # Utilizes index

assert node.element_id == result.element_id

```

This functionality is tested in [`test/sync_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_properties.py) (lines 18-24).

### Validation Constraints and Limitations

The implementation enforces strict constraints to prevent invalid configurations:

- **Nested arrays prohibited**: Instantiating `ArrayProperty(ArrayProperty())` raises `TypeError` during class definition (lines 352-356).
- **Illegal base property attributes**: The `base_property` cannot specify `default`, `index`, `unique_index`, or `required` attributes, as these apply to the container rather than individual elements. Violations raise `ValueError` (lines 357-366).
- **Default value isolation**: The property returns a copy of the default list to prevent shared state mutations across instances (lines 386-388).

## Advanced Usage: Vector Indexes and Semantic Search

For AI and machine learning applications, `ArrayProperty` integrates with Neo4j's vector indexes to enable semantic similarity search:

```python
from neomodel import StructuredNode, ArrayProperty, FloatProperty
from neomodel.indexes import VectorIndex

class Document(StructuredNode):
    embedding = ArrayProperty(
        base_property=FloatProperty(),
        vector_index=VectorIndex(dimensions=512, similarity_function="cosine")
    )

```

This configuration stores 512-dimensional float vectors and creates a vector index for high-performance similarity queries using cosine similarity, as documented in `doc/source/semantic_indexes.rst` (lines 91-114).

## Integration with Cypher Queries

`ArrayProperty` handles serialization automatically through its `inflate` and `deflate` methods (lines 368-386 in [`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py)). When filtering in Cypher queries, you can use array operators:

```python

# Find nodes where array contains specific value

Person.nodes.filter(tags__contains="admin")

# Exact array match (utilizes index if defined)

Person.nodes.filter(tags=["friend", "colleague"])

```

The async API provides identical functionality through [`test/async_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/async_/test_properties.py), ensuring consistent behavior across sync and async operations.

## Summary

- **ArrayProperty** stores ordered lists in Neo4j nodes, implemented in [`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py) (lines 336-386).
- **Untyped arrays** accept any Neo4j-compatible values, while **typed arrays** use `base_property` for element-level validation.
- **Indexing** supports `unique_index` and `index` on the complete array value, not individual elements.
- **Constraints** prohibit nested arrays and illegal attributes (`default`, `index`, `unique_index`, `required`) on base properties.
- **Vector indexes** enable semantic search when combining `ArrayProperty` with `FloatProperty` and `VectorIndex`.
- **Automatic serialization** handles Python list ↔ Neo4j array conversion without manual intervention in both sync and async contexts.

## Frequently Asked Questions

### Can I store nested arrays using ArrayProperty?

No. The `ArrayProperty` implementation explicitly prohibits wrapping another `ArrayProperty`. Attempting to define a field as `ArrayProperty(ArrayProperty())` raises a `TypeError` during class definition (lines 352-356 in [`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py)). For complex nested data structures, model the inner arrays as separate nodes with relationships to the parent node.

### How do I create a unique constraint on individual array elements?

You cannot create constraints on individual elements within an array. The `unique_index` constraint on an `ArrayProperty` applies to the entire array as a single value. Neo4j treats the complete list as one property value for indexing purposes. To enforce uniqueness on individual items, model each item as a separate node with its own `unique_index` constraint and create relationships between the array container and the element nodes.

### Does ArrayProperty support async operations in neomodel?

Yes. `ArrayProperty` functions identically in both synchronous and asynchronous neomodel contexts. The property's `inflate` and `deflate` methods operate on Python lists regardless of whether you use the sync API (`Person.nodes.get()`) or the async API (`await Person.nodes.async_get()`). The test suite validates this behavior in [`test/async_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/async_/test_properties.py), which mirrors the sync tests in [`test/sync_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_properties.py).

### What happens if I pass an invalid type to a typed ArrayProperty?

The property raises a `DeflateError` during the save operation. When you specify a `base_property` (such as `IntegerProperty()`), each element in the list is processed through that property's `deflate` method for validation and conversion. If any element fails type conversion—for example, passing a string to an integer-typed array—neomodel raises `DeflateError` before the data reaches Neo4j, preventing invalid data persistence (as verified in [`test/sync_/test_properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_properties.py) lines 90-100).