Dependencies are not metadata
Most project tools store dependencies as fields hung on a task. A few store them as edges in a graph. The architectural choice determines what the tool can do, what queries it can answer, and which features fall out for free.
The way a project tool stores dependencies tells you everything about what the tool can do.
Most project tools store dependencies as metadata. A task has fields, and one of those fields is "blocked by" or "depends on," and the value of that field is a reference to another task. The dependency is data attached to the task, in the same way that priority, owner, and due date are data attached to the task. The tool's primary object is the task. The dependency is a footnote.
A graph-first project tool stores dependencies as edges. An edge is a first-class object in the data model, equal in importance to the nodes it connects. The dependency isn't attached to a task. The dependency exists in its own right, with the tasks at either end as references. The tool's primary objects are nodes and edges, with neither being subordinate to the other.
This sounds like a small architectural difference. It isn't. The choice between dependency-as-metadata and dependency-as-edge determines what the tool can do, what queries it can answer, what features fall out for free, and what features have to be bolted on at significant cost.
This post is the technical argument for why edges beat fields, and why most project tools made the wrong choice.
The two architectures
Consider the simplest possible model of a project. There are tasks. Some tasks depend on other tasks. The tool needs to store this information and let users query it.
The metadata-first architecture stores tasks in a table. Each row is a task. Each column is a property of the task. One of the columns is "depends on," which contains either null or a reference to another task's ID.
tasks
id | title | status | depends_on
1 | Design API | complete | null
2 | Build backend | in-progress | 1
3 | Build frontend | locked | 2
The edge-first architecture stores nodes and edges in two separate tables. Each node has its own row. Each edge has its own row, referencing two nodes.
nodes
id | title | status
1 | Design API | complete
2 | Build backend | in-progress
3 | Build frontend | locked
edges
from | to
1 | 2
2 | 3
These look almost identical for the trivial case. Three tasks, two dependencies. The data is the same. The queries that ask "what does Build backend depend on?" return the same answer in either architecture.
The architectures diverge the moment the project gets non-trivial.
What edges enable that fields don't
Five capabilities follow naturally from edge-first architecture and don't follow at all from metadata-first architecture. Each one is either impossible or expensive to implement in a metadata-first tool.
Multiple dependencies. A task can depend on more than one other task. In edge-first architecture, this is trivial: add another edge. In metadata-first architecture, the "depends_on" field can only hold one value, so you either change the schema (add depends_on_2, depends_on_3, ad infinitum, which is bad design) or you change the field type to a list (which makes querying harder and breaks the relational model). Most tools that started with single-dependency fields and tried to support multiple dependencies later have ugly compromises in their data model that you can feel through the UI.
Bidirectional traversal. The question "what does Task 5 depend on?" and the question "what depends on Task 5?" are equally important. In edge-first architecture, both queries are symmetric: search the edges table for either endpoint. In metadata-first architecture, the first query is cheap (look up Task 5's depends_on field) and the second query is expensive (scan every task's depends_on field looking for references to Task 5). The asymmetry shows up as a UI asymmetry. Tools that store dependencies as fields are fast at "what blocks this" and slow at "what does this unblock," and you can feel the difference when you use them.
Dependency types. A real project has multiple kinds of relationships. "X must finish before Y can start" is one kind. "X and Y must finish together" is another. "X is a sub-task of Y" is a third. "X is related to Y" is a fourth. In edge-first architecture, edges have a type field, and the model handles all of these uniformly. In metadata-first architecture, each relationship type needs its own field, leading to the field proliferation problem any user of Notion or Airtable will recognize.
Graph algorithms. Once dependencies are edges in a graph, every algorithm that operates on graphs becomes available. Topological sort tells you a valid execution order. Critical path identifies the longest dependency chain. Reachability tells you which tasks can be unlocked from a given starting point. Cycle detection catches errors in your dependency definitions. Strongly connected components reveal portions of the project that are too tightly coupled. None of these are features the tool has to build separately. They're consequences of the data model. Every graph database ships with these algorithms because they're foundational. Every metadata-first project tool has to write them from scratch as features, and most don't bother.
Structural mutations. When you reorganize a project (move a sub-tree, split a task into two, merge two parallel branches), edge-first architecture lets you operate on the structure directly. The graph supports the mutation. In metadata-first architecture, restructuring requires updating the depends_on fields of every affected task, which is error-prone and easy to do wrong. Most project tools that started metadata-first have notoriously bad bulk-edit and restructure features, because the data model doesn't make these operations cheap.
Why most tools chose fields
Given that edges are clearly better, why did most project tools choose metadata-first architecture?
The honest answer is that they didn't think about it.
Project tools inherited from spreadsheets. Spreadsheets store rows of data, with relationships expressed as cell references. The first generation of project tools (Microsoft Project, then early bug trackers, then Jira) carried the spreadsheet model forward. Tasks became rows. Dependencies became fields. The architecture wasn't chosen. It was inherited.
The second generation of tools (Asana, Trello, Linear, Notion) had a chance to reconsider. Most didn't. The reasons varied:
Asana built on a generic database substrate that wasn't graph-native. Adding edge-first architecture would have meant rebuilding the data layer.
Trello started as a kanban tool, where dependencies weren't a first-class concept at all. Dependencies were grafted on later as text-field links.
Linear made deliberate scope decisions to keep the tool focused. Dependencies are supported but not central, and the metadata-first implementation reflects that priority.
Notion built on a flexible database substrate that's powerful but inherently metadata-first. The graph model was incompatible with Notion's core architecture.
In each case, the path of least resistance was metadata-first. The path of greatest capability was edge-first. The path of least resistance won, partly because the engineering cost of edge-first architecture is genuinely higher, and partly because the difference doesn't show up in the demo.
A tool can demo dependencies as a feature: "click here to set blockers." It's hard to demo what edge-first architecture enables without showing a complex project, which most tools don't have at demo time. The architectural choice is invisible to the buyer until they've been using the tool for months and start hitting the walls.
Why we chose edges
Tree was built edge-first because the project work we wanted to support is graph-shaped, and we didn't want to bolt graph features onto a non-graph substrate.
The data model has nodes and edges as peers. Every operation is a graph operation. Every query is a graph query. The UI is a graph visualization. The list view we'll ship is a projection of the graph, computed by topological sort, not a separate data structure that the graph happens to render.
This costs us in some places. Edge-first architecture is harder to implement, harder to scale to massive datasets, harder to make performant for certain operations that lists are good at. The engineering cost is real.
The cost is paid once. The capability is permanent.
Every feature that depends on dependency-aware logic comes for free. Critical path. Topological sort. Available-tier computation. Bidirectional traversal. Cycle detection. Structural mutation. None of these are features Tree had to build. They're consequences of the data model. We get them by virtue of having chosen the right architecture in week one.
A metadata-first tool that decides to add critical path support has to either rewrite its data model (expensive, breaks existing users) or implement critical path on top of a model that doesn't natively support it (slow, brittle, partial). We've watched several tools attempt this. None has shipped a clean implementation, because the architecture is fighting them.
This is the unglamorous reason architecture matters. It's not about elegance or correctness in the abstract. It's about which features are cheap and which are expensive. Pick the right architecture and the right features fall out for free. Pick the wrong one and every additional feature is a fresh fight.
What this means for the user
You can detect a tool's architecture without looking at the source code. The clues are in the UI.
A metadata-first tool will be fast at displaying a single task's dependencies and slow at showing what unlocks when that task completes. The first query is cheap; the second is expensive. The UI reflects this.
A metadata-first tool will struggle with multi-dependency tasks. The "depends on" field will accept one value cleanly and multiple values awkwardly. You'll see this in how the dependencies are displayed (cramped, truncated, requiring a click to expand) and in how they're edited (modal dialogs, ugly multi-select widgets, manual ID entry).
A metadata-first tool won't have native critical path support. It might have it as a paid add-on, or as a separate "timeline" view that recomputes from scratch each time, but it won't feel native because it isn't.
A metadata-first tool will have a dependencies feature with sharp edges. Adding a circular dependency won't be detected. Removing a task that other tasks depend on will leave dangling references. Restructuring a project will require manual cleanup. These are the symptoms of dependencies-as-metadata leaking through.
An edge-first tool, conversely, will treat dependency operations as first-class. Forward and backward traversal are equally fast. Multi-dependency tasks render naturally. Critical path is computed automatically. Cycle detection is enforced. Restructuring updates the graph atomically.
The architecture is invisible. The consequences are everywhere.
The honest tradeoff
Edge-first architecture isn't free. It costs the tool flexibility in some specific ways.
You can't represent arbitrary relationships. The graph supports the relationship types it supports. If your project has an unusual structural pattern (a task that's simultaneously a child of two parents, a workstream that loops back on itself), the graph model will resist. Some real-world workflows need this kind of flexibility, and edge-first tools are wrong for them.
You can't store relationships informally. Metadata-first tools let users encode dependencies as text in a notes field, link in a comment, or hint in a description. The information is unstructured, but it's there. Edge-first tools force the relationship to be explicit and typed. This is more honest but less convenient.
You can't grow the tool into things that aren't graphs. A metadata-first tool can pivot to become a CRM, a wiki, a knowledge base, a task list, anything that fits a flat data model. An edge-first tool is committed to being a graph tool. The flexibility to become other things is gone.
For roadmaps, project plans, and dependency-shaped work, the tradeoff is worth it. For other shapes of work, the tradeoff might not be. Tree is built for the work that's graph-shaped, and we're explicit about the work it isn't built for.
The summary
Dependencies stored as metadata produce tools that are bad at dependencies. The architecture forces every dependency-aware feature to be implemented as a special case, fighting against a data model that doesn't natively support it. The result is tools that nominally support dependencies but feel weak whenever you use that support.
Dependencies stored as edges produce tools that are good at dependencies. The architecture makes every dependency-aware feature cheap, because the data model already supports it. The result is tools where dependency operations feel native, because they are.
The choice happens once, at the start of the project. The consequences last forever. Tree chose edges. The trade-off was deliberate. The architecture is the product.
If you want to see what edge-first project work feels like, join the waitlist.


