Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Neoeloquent Laravel Package

ulobby/neoeloquent

NeoEloquent brings Laravel's Eloquent ORM to Neo4j graph databases. Define graph-backed models, traverse relationships, and run Cypher queries using familiar Eloquent conventions, making it easier to integrate graph data into Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Upgrade check first (v9.9.0 is a hard break for older Laravel). This release requires Laravel 12 or 13 and PHP 8.2+. Before anything else:

composer show ulobby/neoeloquent           # what you're actually on
composer why-not ulobby/neoeloquent 9.9.0  # why the upgrade is blocked

If your constraint is ^9.0, Composer will silently keep Laravel 10/11 apps on 9.8.x — that's intended, not broken. If you wrote ^9.9 on a Laravel 11 app, resolution will simply fail. Confirm your laravel/framework constraint before touching the package version.

Where to look first

  1. config/database.php — the neo4j connection (driver, host, port 7687, credentials). This is the only required config for day-to-day work.
  2. The package README (updated in this release, including test instructions) — namespaces have moved between forks, so confirm the base model class from vendor/ulobby/neoeloquent rather than copying an old snippet.
  3. vendor/ulobby/neoeloquent/tests/ — the suite is now deterministic and runs on PHP 8.2–8.5 × Laravel 12–13 × Neo4j 5.26. Read these tests for authoritative relationship behaviour, especially hasOne/belongsTo edge cases.

First use case. Pick one graph-shaped question you can't answer cheaply in SQL — recommendations, follower/following, org hierarchy, shared-tag similarity. Model it in a dedicated Neo4j connection, leave the rest of the app on your relational database, and prove the traversal in a read-only controller before you commit to migrations.

Implementation Patterns

Hybrid persistence is the default, not a compromise. Keep money, auth, and anything needing multi-row transactions in Postgres/MySQL. Put edges in Neo4j. Do not attempt a cross-store transaction — there isn't one. Mirror changes via model events onto a queue and make the graph consumer idempotent (MERGE, not CREATE).

Graph-backed models. Extend the package's base model, point $connection at your neo4j connection, and set the node label explicitly. Because there is no auto-increment key, use UUIDs or ULIDs as your id and never persist Neo4j's internal node id — it's reused after deletion.

Name your relationship types. hasOne() / belongsTo() without an explicit relationship type no longer fail on Neo4j 5 (fixed in this release), but relying on inferred type names means your Cypher, your Browser queries, and your code all have to agree on a string that was never written down. Declare it — $user->hasOne(Profile::class, 'HAS_PROFILE') — so the edge label in migrations and raw Cypher matches.

Eager load deliberately; the N+1 tax is worse over Bolt. Each lazy relation is a network round trip. Model::with('follows') for shallow graphs; for anything deeper than two hops, drop to raw Cypher. Eloquent can't express variable-length paths ([:FOLLOWS*1..3]), and pretending otherwise produces a cascade of queries.

Raw Cypher for reads, models for writes. Run the traversal through the connection, then hydrate results into model instances so your controllers and resources stay unchanged:

$rows = DB::connection('neo4j')->run($cypher, $params)->toArray();
$users = User::hydrate($rows);

Bind parameters — never interpolate user input into Cypher.

Constraints and indexes belong in migrations, treated as opt-in. Neo4j won't stop you from scanning every node with a given label. Every property you MATCH on in a hot path needs an index; every logical identifier needs a uniqueness constraint. Make the migration idempotent (IF NOT EXISTS) because the migration table behaviour here is less forgiving than Laravel's SQL migrations.

Soft deletes on Laravel 13. This is the fix most apps will actually feel: SoftDeletes, onlyTrashed(), and counts now work on Laravel 13. If you're upgrading to Laravel 13 and carrying a local workaround (a deleted_at property check in a scope, a manual filter in every query), delete it and re-run your tests — the workaround now double-filters or masks the fixed behaviour. On Laravel 12 and below, nothing changes.

Testing. Spin up a real Neo4j 5.26 service container in CI — there is no in-memory equivalent, and mocking the driver hides the query-shape bugs that matter. Match the maintainers' matrix where you can: PHP 8.2–8.5, Laravel 12–13, Neo4j 5.26. Wipe labels between tests or wrap each in a transaction you roll back.

Gotchas and Tips

  • The break is quiet. Composer resolution does the "right" thing for Laravel 10/11 apps, which means a stale 9.8.x install looks identical to a working upgrade. Check composer show after upgrading, not just the absence of errors. And note that Laravel 11 apps get none of the fixes below — including the soft-delete fix, which is Laravel 13 only anyway.
  • Deletion semantics. There are no cascading foreign keys. delete() on a node with edges leaves orphans or fails depending on how you query it — reach for DETACH DELETE in raw Cypher, and clean edges explicitly in application code. Verify your soft-delete expectations specifically: a "trashed" node is still in the graph, still matched by raw Cypher, and still counted by anything that doesn't go through the model.
  • Property types. Neo4j stores what you give it. Arrays of scalars are fine; nested objects and non-UTC datetimes will bite you. Normalise dates on write and keep a single cast definition per attribute — the package's casting plus Cypher-level filtering can disagree silently.
  • Counting is not free. count() over a relationship is a graph traversal, not an indexed lookup. It's also an area that has moved recently (the release notes call out counts alongside soft deletes) — pin behaviour with a test before you depend on it in a dashboard.
  • Aggregates and withCount are partly implemented. Verify each aggregate you use against the package tests rather than assuming Eloquent parity; unsupported ones fail confusingly rather than loudly.
  • Debugging slow queries. Enable the connection's query logging, capture the exact Cypher the package builds, and run it in Neo4j Browser with PROFILE. Nine times out of ten the fix is a missing index or an accidental Cartesian product, not the ORM.
  • Eager loading deep graphs explodes memory. with() on a high-degree node can pull tens of thousands of rows. Paginate, cap depth, or return projections instead of full nodes.
  • Extension points worth knowing. The model's connection and label properties, a custom relationship-type resolver if you must, attribute casts, and raw connection access for the queries Eloquent can't express. Prefer raw Cypher over forking the relationship classes — this package's internals move between releases, as the Travis→GitHub Actions CI change and the Neo4j 5 fixes show.
  • Neo4j version drift. CI certifies Neo4j 5.26. Neo4j 4.x and pre-5.26 setups are untested by this release — the reported hasOne/belongsTo bug was itself a Neo4j 5 regression, so treat server upgrades as code changes and run your suite against the target image.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect