Download Latest Version v3.13.1 source code.zip (13.4 MB) Google Add to Preferred Sources
Home / v3.13.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-09-05 36.4 kB
v3.13.0 source code.tar.gz 2026-09-05 9.5 MB
v3.13.0 source code.zip 2026-09-05 13.4 MB
Totals: 3 Items   23.0 MB 0

Memgraph v3.13.0 - September 9th, 2026

⚠️ Breaking changes

  • The APOC compatibility names apoc.convert.fromJsonList and apoc.convert.toJson now resolve to the C++ convert module (convert.from_json_list / convert.to_json) instead of the Python json_util implementations. Output can differ — especially for nodes, relationships, paths, points, and temporals. Call json_util.* explicitly if you need the previous Python behavior, or update consumers for the new structured / ISO-8601 JSON forms. #4443
  • The COORDINATOR privilege was removed — it never gated any operation. It is no longer accepted in GRANT / DENY / REVOKE statements, which now fail with a syntax error, and it is no longer reported by SHOW PRIVILEGES or included in GRANT ALL PRIVILEGES. Remove any GRANT COORDINATOR / DENY COORDINATOR / REVOKE COORDINATOR statements from provisioning scripts and update tooling that compares against the full privilege list. No data migration is required: a stale grant in an existing deployment is never reported and never checked. The new COORDINATOR_READ and COORDINATOR_WRITE privileges are not a replacement — they are coordinator-only and are rejected on data instances. #4399
  • Connecting to a coordinator with a username and password is no longer always accepted. Once --auth-module-mappings is set, the enterprise license is valid, and a role holding COORDINATOR_WRITE exists, basic authentication is denied in favor of SSO. Until all three hold, the previous passthrough behavior is unchanged. #4399
  • Inside a bare CALL {} subquery, a pattern that mentions an outer variable without importing it now opens a fresh binding instead of silently reusing the caller’s. Queries that relied on the old leak return different results with no error. Import explicitly with CALL (n) {, CALL (*) {, or a leading WITH n. Some invalid pattern-comprehension shapes that used to abort the server now raise a clear query error instead (create+reference in the same clause, reusing a bound relationship, variable-length expand from a node written in the same query part). #4487
  • In path.expand / path.expand_config / path.subgraph_* relationship filters, <TYPE> now means incoming TYPE (the old reciprocal-pair reading is gone). * in a label filter is a wildcard, not a literal label. Unknown config keys are errors instead of being ignored. Calls that relied on the old readings can return different results or fail without a code change. #4530
  • SHOW INSTANCES is now strongly consistent and always answered by the leader coordinator. A follower that cannot reach the leader no longer falls back to reporting the cluster from its own local Raft state with unknown health — it returns an empty result set with a LeaderNotReachable warning notification instead. Tooling that parses SHOW INSTANCES should treat an empty result as "cluster state unknown, retry" rather than "no instances registered". A data instance that is down now reports the role recorded in the Raft log (main / replica) instead of an unknown role. #4492
  • TERMINATE TRANSACTIONS now requires transaction ids to parse in full. Ids with trailing characters previously terminated the transaction matching the numeric prefix, and unparseable ids were reported back as an attempt on 18446744073709551615; both now raise an error. #4534
  • size(), substring(), left(), and right() now count characters, not bytes. For non-ASCII text, lengths and cut positions can change (for example size('中') is 1, not 3). Recheck any stored results that depended on the old byte offsets. #4586
  • A number that starts with 0 is now octal, so 09 and 018 are parse errors instead of 9.0 and 18.0. Drop the leading zero for decimal, or keep it for octal (010 is still 8). #4588
  • A RETURN inside EXISTS { ... } now affects the answer. Queries that relied on the body RETURN being ignored may return different results after upgrading. #4597
  • Whole-number strings that do not fit in a 64-bit integer now raise an error in toInteger() instead of wrapping to a wrong value. Use toIntegerOrNull() if you want null for those inputs. #4589
  • single() returns null when the predicate is null for any list element, instead of true. Queries that treated a null predicate as a match will see different results. Wrap with coalesce(single(...), false) if those rows should be treated as not matching. #4590
  • split('', ...) returns [''] rather than an empty list, so a non-null string always yields at least one field. Update callers that assumed splitting an empty string produced no fields. #4591
  • The default value of --metrics-format changed from JSON to OpenMetrics. A deployment that relied on the JSON metrics endpoint without setting the flag now serves OpenMetrics after upgrading. Either update your monitoring dashboards, as described in Migrating from JSON to OpenMetrics, or set --metrics-format=JSON explicitly. The deprecated JSON endpoint remains available for several releases. #4678
  • The cross_database module (and the deprecated migrate.* aliases) now requires Memgraph Enterprise. Community deployments that called these procedures need an Enterprise license after upgrading. #4726

🐞 Bug fixes

  • Fixed a query planning crash when extract() was used inside WHERE (for example WHERE 'x' IN extract(v IN n.list | v.field)). Those queries now run as written. #4081
  • Identifiers may now include currency symbols such as $ anywhere except as the first character (for example price$), matching openCypher. Whitespace between $ and a parameter name (for example $ 1) is also handled correctly. Previously both cases could confuse the query stripper and crash the server. #4283 #4285
  • Text and vector search now respect fine-grained label and property permissions. Hits the caller cannot read are filtered out, and text_search.aggregate / text_search.aggregate_edges return an error unless every indexed property is readable. #4316
  • Running many one-off queries that differ only in large inlined values (for example embeddings) no longer lets the query cache grow without bound and exhaust memory. The cache is capped by --query-ast-cache-max-size (default 1000; 0 disables it), and each entry also uses less memory. #4334 #4445
  • Fixed parallel index scans (USING PARALLEL EXECUTION) so a filter that evaluates to null returns no rows instead of treating the filter as absent and returning every matching edge or node. #4406
  • The collections.* functions and procedures now accept NULL list and scalar arguments instead of failing argument validation. Each function returns a defined result (for example collections.sum(null) → null, collections.sort(null) → [], collections.contains(null, x) → false), matching the compatibility-layer behavior. #4416
  • Fixed stale coordinator entries in the HA routing table and a possible coordinator crash on REMOVE COORDINATOR. Coordinators now deduplicate entries when applying Raft logs and snapshots. #4444
  • Fixed path.subgraph_all and path.subgraph_nodes so their config options work as expected. #4447
  • Under heavy concurrent load, operations that need exclusive access to the database could hang indefinitely while shared readers kept arriving. Those exclusive waiters now take priority so the hang no longer happens. #4450
  • Fixed concurrent SET STORAGE MODE handling so mode switches are safe under load. #4451
  • Fixed a crash when LOAD PARQUET hit invalid values (for example a time outside Memgraph’s supported range). The query now fails with an error instead of taking down the server. #4454
  • Fixed LOAD PARQUET silently storing wrong timestamps or durations when converting large temporal values from Parquet. Those cases now fail with a clear query error instead of corrupting data. #4455
  • Fixed a rare crash in garbage collection under heavy concurrent writes when indexes or unique constraints are defined. #4475
  • Fixed pattern comprehensions in WITH … WHERE / ORDER BY so they correlate with the bound variable instead of scanning the whole graph; fixed CALL {} overwriting outer variables it did not import; and fixed related wrong results for named paths and WITH + ORDER BY + WHERE. #4487
  • Fixed a crash when multiple sessions printed query plans at the same time (for example concurrent EXPLAIN / PROFILE, or query-plan logging). #4489
  • Pattern comprehensions now see writes made earlier in the same query part. Reading a list like [(p)-[:ACTED_IN]->(m) | m] after a SET / CREATE no longer returns empty or wrong results. Expanding from a node that a preceding clause deleted now raises an error instead of counting relationships that no longer exist. #4499
  • Fixed TTL sometimes never running after it was configured or enabled, so expired data is cleaned up as scheduled. #4513
  • SET COORDINATOR SETTING 'instance_health_check_frequency_sec' TO '0' is now rejected with an invalid-argument error instead of crashing the coordinator later (for example on REGISTER INSTANCE or restart). #4522
  • Fixed silent data loss when a WAL file other than the last one in the chain was damaged. Recovery used to apply the readable prefix of that file and then apply the following files in full, coming up with an incomplete dataset without reporting anything; on a replica the divergence never healed because the replica reported the later timestamp and main considered it caught up. Damage in a completed (finalized) WAL file is now fatal: the database fails recovery instead of starting stale, and a replica stops applying the rest of the chain. A WAL file that was still being written when the process crashed is unaffected and is still truncated to its last whole transaction. Recover such an instance with --storage-allow-recovery-failure plus RECOVER SNAPSHOT, or from a backup. #4528
  • Fixed several path module issues: traversals honor query timeout / TERMINATE TRANSACTIONS / shutdown; deep expansions error instead of crashing; path.create no longer aborts on a missing rel key; and filter / hop-bound edge cases that produced wrong or empty results. #4530
  • TERMINATE TRANSACTIONS no longer reports killed: true for a transaction the caller is not authorized to terminate. Such a match now reports killed: false, indistinguishable from an id that does not exist. #4534
  • Fixed a crash when writing a property covered by a nested index if the value has nothing at the indexed path (for example CREATE (:T {m: 1}) with an index on :T(m.k)). #4550
  • path.slice clamps out-of-range offset / length instead of throwing, and path.slice, path.elements, and path.combine accept a null path. A negative length other than -1 (to the end) now returns a subpath with no relationships rather than the rest of the path. #4552
  • *KSHORTEST|k now returns up to k paths for each input row, not for the whole query. |k can also be an expression from the current row (for example -[*KSHORTEST|n.k]->). With an inlined edge property map, only matching paths count toward k. #4559
  • Negative or empty *KSHORTEST depth bounds and a negative |k now raise a query error instead of returning no rows (or scanning the whole graph first). #4559
  • EXISTS { ... } subquery bodies now behave as expected: bodies that always match evaluate to true instead of crashing the server, and EXISTS in WITH projections and ORDER BY no longer fails with a spurious aliasing error. #4560
  • Replicas no longer time out during recovery steps that run long inside a single delta, such as populating an index, validating a constraint, loading a snapshot, clearing storage before a reset, or aborting an interrupted two-phase commit. A replica now reports progress on a fixed time interval for as long as the work keeps advancing, instead of after a fixed number of processed deltas, so the main no longer drops the connection mid-build and leaves the replica unable to converge. A replica that stops advancing stops reporting, so a genuinely stuck replica is still caught by the main's timeout. As a consequence, the deltas_batch_progress_size coordinator setting no longer has any effect; it stays readable and settable so existing configurations keep working across an upgrade, and will be removed in a future release. #4557
  • Filters on a variable imported into a scoped CALL (v) { ... } subquery now use a label-property or id() index instead of scanning every node or edge once per input row. MATCH ()-[e:TYPE]->() WHERE id(e) = ... no longer returns an edge of the wrong type. #4561
  • Variables imported by CALL (v1, v2) { ... } and CALL (*) { ... } now stay bound after a WITH inside the subquery. Previously an inner WITH that omitted them could return wrong rows, overwrite the outer variable, or CREATE/MERGE a new node instead of using the imported one. #4578
  • Fixed crashes and unbounded index growth in IN_MEMORY_ANALYTICAL when indexes are enabled. Index entries are now removed before the nodes or edges they point to are deleted. #4580
  • reverse() now reverses characters, not bytes, so accented text, Chinese, and emoji come back readable instead of as broken UTF-8. #4585
  • size(), substring(), left(), and right() now work on whole characters, so cuts no longer split multi-byte text into invalid UTF-8. #4586
  • Integer literals with a leading zero are no longer treated as floating-point values, so they get a proper integer range check instead of a silent approximate double. #4588
  • toInteger() now converts whole-number strings exactly. Values near the 64-bit limits no longer round to a neighbouring integer (for example the largest integer no longer comes back as the smallest). #4589
  • An invalid timezone now raises a clear argument error instead of "An unknown exception occurred". UTC offsets such as +01:00 and Z are accepted as well as timezone names. #4592
  • A RETURN inside EXISTS { ... } is now planned instead of ignored, so DISTINCT, SKIP, LIMIT, and aggregation in the body affect the answer. Results can change without an error — recheck any query that relied on the body RETURN being ignored. #4597
  • Replication and coordination now log cluster state changes at INFO instead of TRACE, so you can see failover, role, and leadership changes without enabling per-delta trace logs. The default log level stays WARNING. #4599
  • Query log masking no longer leaks part of a secret when the value contains quotes or is missing a closing quote. Those values are now fully redacted in logs. #4629
  • EXPLAIN no longer shows a Limit above an EXISTS { ... } or COUNT { ... } subquery branch. That operator did not actually limit the branch, so the plan looked wrong. Query results are unchanged. #4630
  • Type constraints now accept zoned datetimes whose timezone is a numeric UTC offset, such as +01:00, instead of rejecting them as the wrong type. #4635
  • Near the memory hard limit, Memgraph no longer crashes by refusing allocations the runtime needs for itself. Query allocations are still limited as before. #4646
  • Repeated runs of variable-length expands that return distinct vertices (for example with DISTINCT) are faster, because those queries no longer replan on every execution. #4650
  • Setting a list property that is also covered by a vector index no longer crashes the server when the node already has a typed-list constraint. The value is checked like any other list. #4653
  • List comprehensions whose WHERE predicate is NULL for an element now omit that element and keep the rest of the list, instead of returning NULL for the whole result. A WHERE predicate that is neither a boolean nor NULL is rejected with an error. #4665
  • LOAD PARQUET and LOAD JSONL accept URLs of any length, including long signed URLs. A download in progress can be stopped with TERMINATE TRANSACTIONS, and failures that cannot succeed on retry are reported as client errors rather than transient ones. #4672
  • Lists that hold large integers are compared and sorted correctly. Values that differed only in the high bits no longer compared equal. #4712

🛠️ Improvements

  • Memgraph is now built with a distro-agnostic toolchain, so DEB and RPM packages install on a wider range of Linux distributions that meet GLIBC >= 2.31 and Python >= 3.10. #3587
  • node2vec and node2vec_online now use a C++ word2vec implementation instead of the unmaintained Python gensim package. Usage is unchanged, expect faster runs. #4319
  • MAGE is now built and packaged from the same unified CMake / Conan tree as Memgraph. Build it with build.sh --mage on or --mage only; the old mage/setup Python script is removed. Only affects people building MAGE from source — prebuilt packages are unchanged. #4348
  • build.sh --target now accepts several targets in one invocation (for example --target memgraph memgraph__unit), so you can build multiple targets with a single configure step instead of one run per target. #4404
  • Queries that use query-module functions or CALL procedures are now plan-cached instead of being re-parsed and re-planned on every run. Module reloads stay safe; only module-dependent queries are invalidated, and the next execution picks up updated code. #4461 #4482
  • In in-memory transactional mode, CREATE INDEX / CREATE CONSTRAINT no longer stall behind garbage collection (and GC no longer waits on those DDL statements). Under index-heavy workloads this removes GC-correlated latency spikes on index and constraint creation. #4468
  • SHOW TRIGGERS and DROP TRIGGER no longer take a storage write lock. CREATE TRIGGER uses a read accessor only. Clients that poll SHOW TRIGGERS often (for example Memgraph Lab) no longer contend with writers for that reason. #4495
  • Connecting Lab is less expensive under load: its connect-time health-check queries no longer open a storage transaction or pin a tenant. #4496
  • The self-contained Memgraph+MAGE offline installer is quieter (installer noise goes to a log file) and is published with the other release artifacts on the download hub. #4500
  • Garbage collection is faster on databases with many indexes: it only visits indexes that recent writes could have touched. #4508
  • Recovery from WAL files is roughly 35% faster. Each WAL file now records its timestamp range and transaction count in its header, so deciding which files to recover from no longer requires parsing every file end to end, and replaying a file parses it once instead of twice. This also speeds up replica recovery and the WAL cleanup that runs after every snapshot. #4528
  • Path config filters are stricter: empty or bare filter entries, * in a relationship filter, and blank sequence steps are rejected instead of producing wrong results. On path.subgraph_nodes / path.subgraph_all, bfs and uniqueness are accepted and ignored (those procedures are always breadth-first, one visit per node). #4530
  • Queries that filter with IN on an indexed label and property (for example MATCH (x:L) WHERE x.p IN ["a", "b"]) now get accurate cardinality estimates, so the planner picks better index plans for those filters. #4538
  • Writing and loading a snapshot no longer fills the operating system's file cache, so more memory stays free for queries while it happens. This works automatically; --storage-snapshot-writeback-window-mib tunes how much of a snapshot is cached before being written to disk (0 restores the old behaviour). #4546
  • Variable-length expands that return distinct vertices (for example with DISTINCT) no longer walk every edge-unique path. Memgraph can use a pruning breadth-first search instead, which is much faster on wide or dense graphs. #4558
  • CONTAINS, STARTS WITH, and ENDS WITH on an indexed label and property now use that index instead of scanning every node. #4562
  • Replicating edge deletions is much faster on replicas. Large deletes that were previously quadratic on the replica now scale with the number of edges deleted, as they do on MAIN. #4564
  • WHERE NOT NOT n.prop = 42 (and similar double negation) now uses a property index instead of scanning the label. Results are unchanged. #4594
  • In IN_MEMORY_ANALYTICAL, CREATE INDEX and DROP INDEX no longer block read queries. You can also build several supported indices in parallel, while writes are still held off until the build finishes. #4633
  • Fixed unnecessary work on property writes when fine-grained property permissions are not configured. #4639
  • Indexed STARTS WITH filters no longer re-check the prefix after the index scan, so those queries do less work per row. Results are unchanged. #4643
  • Commits on MAIN with replicas are faster: encoding work for replicas runs in parallel with writing the local WAL, so commit time no longer grows as steeply with the number of registered replicas. #4645
  • Indexed CONTAINS, ENDS WITH, and REGEX filters are faster when many nodes share the same property value: after one value fails the filter, the scan skips the rest of that value instead of checking every duplicate. #4647
  • Aggregations such as count(), sum(), and avg() are faster, especially without a grouping key, because they do less work per input row. Results are unchanged. #4655
  • path.expand_config, path.expand, path.subgraph_nodes, and path.subgraph_all are substantially faster, especially with selective filters or a single relationship direction. #4727
  • Cluster management queries forwarded from a follower coordinator to the leader now have explicit RPC timeouts, so a Bolt session can no longer block indefinitely against a leader that is reachable but stuck. The same applies to MAIN-to-REPLICA system transaction messages (auth, multi-tenancy, parameters), which now time out after 10s and defer to system recovery. The unused EnableWritingOnMainRpc and its Prometheus counters were removed. #4399
  • YIELD LEADERSHIP and SHOW COORDINATOR SETTINGS can now be run on any coordinator — followers forward them to the leader instead of failing or answering from local state. When no leader can serve a cluster query, Memgraph now says so explicitly: read queries (SHOW INSTANCES, SHOW COORDINATOR SETTINGS, SHOW REPLICATION LAG) return no rows with a LeaderNotReachable warning, SHOW REPLICATION LAG additionally reports why the lag is unavailable via ReplicationLagUnavailable (no current main, main unresponsive, leader still taking over, stale leader view), and ADD COORDINATOR, REMOVE COORDINATOR and UPDATE CONFIG fail with a clear "coordinator is not a leader" error instead of a misleading one. #4492

✨ New features

  • Added global vertex-property indexes with CREATE GLOBAL INDEX ON :(prop) (and DROP GLOBAL INDEX ON :(prop)). They speed up property lookups across all nodes when there is no shared label, for example MATCH (n) WHERE n.uid = '123' RETURN n. #4353
  • Added collections.disjunction, collections.subtract, and collections.duplicates to the MAGE collections module for set-style list difference, subtraction, and finding repeated values. #4415
  • Added map.get and map.merge_list to the MAGE map module. Existing helpers such as map.merge and map.set_key now treat a null map as empty (and a null key as a no-op) instead of failing, and accept nodes or relationships by using their property maps. #4417
  • Added text.compare_cleaned(text1, text2) to the MAGE text module. It compares two strings for equality after keeping only ASCII letters and digits (lowercased) and dropping everything else; NULL arguments return false. #4435
  • C++ query-module authors can return a value whose type is only known at runtime with a single Result::SetValue(value) call, instead of switching on the value's type to pick a typed overload. #4436
  • Added convert.from_json_map, convert.from_json_list, convert.to_map, and convert.to_json for parsing and serializing JSON, with an optional path selector on the from_* helpers and structured output for graph and temporal types from to_json. #4443
  • Added search.node and search.node_all procedures that find nodes by a {label: property} map, a comparison operator, and a value. A property list per label is OR-ed; search.node de-duplicates by node while search.node_all keeps duplicates. An existing label-property index is used automatically when available. #4460
  • --coordinator-id=0 is now a valid coordinator id (previously rejected). #4483
  • CREATE RANGE INDEX FOR ... ON ... now works for nodes and relationships and creates Memgraph’s usual property index. #4486
  • SSO authentication on high availability coordinators (Enterprise). Coordinators authenticate OIDC, SAML and Kerberos connections against a Raft-replicated set of roles and enforce two privileges, COORDINATOR_READ and COORDINATOR_WRITE. Manage them with CREATE ROLE, DROP ROLE, SHOW ROLES, GRANT / REVOKE COORDINATOR_READ | COORDINATOR_WRITE | ALL PRIVILEGES, and SHOW PRIVILEGES FOR ROLE on any coordinator — follower queries are forwarded to the leader. Basic authentication stays open until a COORDINATOR_WRITE role exists, so no coordinator restart is needed to roll SSO out, and it reopens if the license becomes invalid so a coordinator can never lock every session out. #4399
  • SHOW VERSION can now be run on coordinators, alongside the other read-only introspection queries such as SHOW CONFIG and SHOW BUILD INFO. It previously failed with Coordinator can run only coordinator queries!. On coordinators it is a COORDINATOR_READ query, so an SSO role with only COORDINATOR_READ granted can run it. #4535
  • Added the SHOW ROUTING TABLE query, which shows the routing table a coordinator hands out to bolt+routing clients as WRITE, READ and ROUTE rows. It can only be run on a coordinator, is always answered from the leader's state, and returns an empty table if the leader cannot be contacted. #4502
  • EXISTS { ... } and exists((a)-[]->(b)) now work in WITH / RETURN projections, WITH ... WHERE, ORDER BY, and aggregate arguments, not only in a MATCH WHERE. You can write WITH p, EXISTS { MATCH (p)-[:ACTED_IN]->() } AS hasActed instead of rewriting it as an OPTIONAL MATCH plus a count. #4504
  • Added TERMINATE TRANSACTIONS "*", which terminates every transaction the caller is authorized to terminate across all databases, instead of naming ids one by one. The caller's own transaction is skipped, transactions it may not terminate are omitted from the result, and rows come back ordered by ascending transaction id. The wildcard cannot be combined with ids. #4534
  • A data instance in a high availability cluster can now use the IN_MEMORY_ANALYTICAL storage mode for a bulk import: unregister the replicas, switch to analytical, import, switch back to IN_MEMORY_TRANSACTIONAL and register the replicas again. The switch back writes a snapshot of the imported data, archives the superseded durability files and restarts WAL numbering, and replica recovery detects that the imported data exists in no WAL file, so a re-registered replica catches up from that snapshot without wiping its data directory. Starting a data instance with --storage-mode=IN_MEMORY_ANALYTICAL remains forbidden. See bulk import in analytical mode. #4510
  • Added property-value descriptions: attach a human-readable label to a specific property value with SET DESCRIPTION ON PROPERTY … VALUE …, resolve it in queries with description(property, value), and manage them with the existing SHOW / DELETE DESCRIPTION commands. #4526
  • Added path.expand_config(start, config) and extended the path config map with node-identity filters, limit, uniqueness (including NODE_GLOBAL), and repeating label/relationship sequences. path.subgraph_nodes and path.subgraph_all accept the new filter keys too. #4530
  • Added --storage-omit-vector-index-properties-on-return (also a runtime database setting, default false). When enabled, properties backed by a vector index are omitted from whole nodes and relationships returned to the client, which cuts payload size for embeddings. Explicit access such as n.embedding still returns the value; dumps, WAL, and replication are unchanged. #4556
  • *KSHORTEST now accepts a filter lambda, -[*KSHORTEST (r, n | pred)]->, so you can narrow the search while expanding instead of filtering whole paths afterwards. #4559
  • EXISTS { ... } can now be used inside a CASE expression, including in the condition (for example CASE WHEN EXISTS { ... } THEN ... END). #4596
  • Added COUNT { ... }, which counts the rows a subquery body produces (for example RETURN COUNT { MATCH (p)-[:KNOWS]->(f) }). Use it instead of building a list with a pattern comprehension and calling size(). #4598
  • If a write cannot reach every SYNC replica but still commits on MAIN (and reachable replicas), the query no longer fails with an exception. A WARNING notification is returned instead, so the client result matches what was actually committed. Writes that are rolled back everywhere (for example STRICT_SYNC) still raise an error as before. #4601
  • Added COLLECT { ... }, which returns a list built from a subquery body's single return column, evaluated once per outer row (for example RETURN COLLECT { MATCH (p)-[:KNOWS]->(f) RETURN f.name }). An empty match yields [] rather than null. #4632
  • Added --storage-rocksdb-keep-log-file-num (default 1000), which caps how many RocksDB info log files are kept per RocksDB instance. Since every restart rolls the current info log into a new file, lowering it helps on deployments with constrained disk space. --storage-rocksdb-info-log-level and the new flag now apply to every RocksDB instance Memgraph opens — the key-value stores backing authentication, triggers, streams, settings and replication or high availability state — and not only to the ON_DISK_TRANSACTIONAL storage. #4579
Source: README.md, updated 2026-09-05