Gram graph exchange format

Gram is a textual format for data graphs, inspired by Cypher and extended to anticipate the greater expressiveness of GQL.

Named values are packed into records, qualified with labels, given identity, and organized into expressive patterns. It's JSON for data graphs!

In gram, everything is a path. Nodes and relationships are special cases of a path. A graph is composed by writing a sequence of paths, which makes gram ideal for streaming (even non-graph) data.

The reference implementation is written in TypeScript and produces an AST.

Roadmap targets include:

  • port to other languages
  • integrate with D3, cytoscape, graphology, ...
  • add import/export from Neo4j using Relate framework

Thoughts? Opinions? Complaints? I'd love to hear them all. :slight_smile:


An introductory blog post about gram, explaining some of the motivation.

1 Like

It's quiet around here, but this looks very interesting!

Is it compatible with cypher or just visually similar?

I'm not sure if neo4j uses cypher as a dump format, like SQL, but is the following from your blog expected to be able to be imported into neo4j verbatim? It might be nice if you had a subset which was legal cypher.

(a:Author { name:"Andreas Kollegger", address: { city:"MalmΓΆ", country:"Sweden" }})
(b {title:"Gram: a data graph format"})
(c {when:date`2021-01-21`})

And presumably you looked at dot and other graph formats? Why did you decide to build something new?


Well timed! As a side project, Gram hasn't had attention for a while but the summertime is great for picking it back up.

Gram is inspired by Cypher and previous work by @technige . The goal is to explore an exchange format for graphs across client-side libraries (mostly visualization) and server-side databases like Neo4j. A compatible subset of graph features is already possible using existing formats. Instead, I wanted to explore a broader set of graph features, accepting that individual targets may not support all those features.

So, Gram prefers lossiness on the consumer side, not the producer. For Neo4j any Cypher result can be captured in Gram, but Neo4j may not preserve all information represented in Gram. That feels uncomfortable yet is not new, as Cypher results can be broader than Neo4j's persistent model.

Some practical problems also informed the direction:

  1. "The d3 problem" -- visualizing a graph often adds position and styling information to the graph itself. Where does that stuff go?
  2. "The route 66 problem" -- a path is a thing. Having discovered (or defined) a path, how can we say something about the path itself? Where does that go?
  3. "The streaming problem" -- stream processing applies to a sequence of elements. To stream a graph, what's the type of the elements, and what's their order?

I agree that it'd be useful to have a strict subset which is copy-and-pasteable Cypher. I've loosely followed the approach of tooling in the unifiedjs collective, thinking that Gram tooling could have plugins and toolsets to adapt to different needs.

Things like dates and spatial points would need to accept both the function call date() and the template literal syntax. Does that seem sensible to you?


So Gram has to be able to specify everything cypher does and more? seems a tall order given its quite a loose spec. There's also that backup format for cypher, which I think is distinct from the query language.

maybe you can have a linter to see if a subset of your gram would work as legal data to import into a neo4j DB at least? otherwise going to gram means stepping outside the cypher ecosystem.

if it's too fully specced from day one, it's going to be hell for anyone to implement viewers or other consumer tools too?