# What are the benefits of async relationship?

**URL:** <https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688>\
**Category:** Ember Data\
**Created:** [June 18, 2019, 11:14am UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688 "2019-06-18T11:14:19Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ondrejsevcik](https://avatars.discourse-cdn.com/v4/letter/o/ed655f/32.png) [@ondrejsevcik](https://discuss.emberjs.com/u/ondrejsevcik)\
**Post date:** [June 18, 2019, 11:14am UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/1 "2019-06-18T11:14:19Z")

</div>

This question was [already asked once](https://discuss.emberjs.com/t/what-are-the-advantages-of-async-relationships/11667) but there was no satisfying response. Let’s try to answer this question again in 2019.

I’ve found this article arguing against using async relationships and to be honest, it makes sense. Accessing model property and as a side effect triggering server request is not what a new developer would expect. It adds more complexity and on top of that, we’re losing power to control how and when the requests are made.

So why is it that ember-data has by default async relationships? What are the benefits of that over sync relationships?

> **[The case against async relationships in Ember Data](https://embermap.com/notes/83-the-case-against-async-relationships)**
>
> If you've spent any time around Sam and me, you've probably heard us talk about our frustrations with Ember Data's async relationships. In this post I'll outline why we think using { async: true } is so problematic. I'll also discuss the patterns we...

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [June 18, 2019, 1:14pm UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/2 "2019-06-18T13:14:03Z")

</div>

One reason it’s the default is simply because it _has been_ the default—someone decided that’s how it would be at some point a long time ago, and inertia kept it that way. Changing it requires a major version/breaking change release. If you take a look at some of the big picture items outlined in @runspired’s [#EmberJS2019 blog post](https://runspired.com/2019/06/17/emberdata2019/), you’ll note that there are a _bunch_ of changes inbound for Ember Data, though, and I’d venture that the Ember Data Core Team would be happy to work through an RFC arguing to flip the default!

---

<div class="post-metadata">

**Author:** ![ef4](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/ef4/32/13470_2.png) [@ef4](https://discuss.emberjs.com/u/ef4)\
**Post date:** [June 18, 2019, 1:48pm UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/3 "2019-06-18T13:48:58Z")

</div>

I can provide a little of the original rationale for async relationships.

When you’re just starting out, they’re really convenient. They let you traverse the graph of models lazily, on-demand and not need to stop and worry about it. They’re particularly good if all your data access tends to happen in templates, because templates are declarative and can cleanly deal with any asynchrony without you needing to worry about it. While you’re on that happy path, async relationships take what would have been an exception and make it Just Work. That’s nice and it means one less thing for a newbie to deal with at that moment in time. It means you can first spend effort getting your UI right, and later when you’re ready spend effort reducing the number of network requests you can do that separately (and maybe you’ll never even bother with step 2, based on the requirements of your app).

But I still agree with pretty much everything in the article. As soon as people go beyond the basic cases, there’s a cliff you step off and the asynchrony is more painful than helpful. I think people hit the cliff early enough that it’s not worth it. Unfortunately that does mean pushing more explicit work onto users earlier in the process.

---

<div class="post-metadata">

**Author:** ![samselikoff](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/samselikoff/32/16581_2.png) [@samselikoff](https://discuss.emberjs.com/u/samselikoff)\
**Post date:** [June 19, 2019, 3:32am UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/4 "2019-06-19T03:32:33Z")

</div>

I will just add that Rails faced similar footguns with ActiveRecord, which influenced the design of Ecto (Phoenix’s data layer) to throw compile-time errors if a template ever tried to render data that wasn’t explicitly sideloaded by the programmer.

When I learned this it had a big impact on my opinion of the problem space, because it was basically an admission that data loading is too complex (at this stage of the game) to be delegated to an automated tooling layer.

---

<div class="post-metadata">

**Author:** ![ondrejsevcik](https://avatars.discourse-cdn.com/v4/letter/o/ed655f/32.png) [@ondrejsevcik](https://discuss.emberjs.com/u/ondrejsevcik)\
**Post date:** [June 19, 2019, 11:10am UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/5 "2019-06-19T11:10:21Z")

</div>

Thanks for sharing your thoughts.

Personally, I think Ember defaults should be set in a way that the app can grow big and still be a maintainable piece of software. The “easy for newbies” part should be “nice to have” in most cases.

I’m not sure if ember-data can recover from this, or at least it won’t be easy. In our case, we have close to 300k+ lines of JS code and so far I couldn’t think of any way to go from async to sync relationships in a safe manner, without introducing bugs as a side effect of that. And I think this will be an issue with any larger app out there. If ember-data changes this default in the next major version, we probably won’t be able to upgrade unless there will be a nice and safe upgrade path.

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [June 19, 2019, 1:41pm UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/6 "2019-06-19T13:41:19Z")

</div>

That’s precisely why it _remains_ the way it is today: that’s been true for a lot of apps for a long time. I’m hopeful that the work the Ember Data team is aiming to do over the next many months will unlock not just better patterns but better patterns _with a migration story_.

---

<div class="post-metadata">

**Author:** ![runspired](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/runspired/32/18654_2.png) [@runspired](https://discuss.emberjs.com/u/runspired)\
**Post date:** [June 19, 2019, 4:53pm UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/7 "2019-06-19T16:53:24Z")

</div>

FWIW There is a plan to move from async to sync with a nice migration path, and it’s much easier than you might think.

It starts with understanding that the data structure we return from both sync and async relationship access is _too flat_. Relationships need information about meta/errors/links beyond just the records that they contain. Today this information is difficult to access generally and especially hard to access within a template.

Were we to introduce a better primitive that was slightly less flat we could use the opportunity to also change how you access that data structure both in your JS code and in your templates.

For example, imagine relationships had the following interface for their resolved data

```nohighlight
interface Relationship {
   data: Identifier|Identifier[]|null;
   links?: Links;
   errors?: Error[];
   meta?: object 
}

```

and to access the records for a relationship in your JS

```nohighlight
let data = await fetchRelationshipData(record.myRelationship);

```

and to access those same records in your template with an async boundary in the template

```nohighlight
{{#let (fetch-relationship-data record.myRelationship) as |list|}}
  {{#each list as |item|}}
      ...
  {{/each}}
{{/let}}

```

Or to use the available errors

```nohighlight
{{#each record.myRelationship.errors as |error|}}

{{/each}}

```

Or to just output a count or some other meta info

```nohighlight
Showing 1 - {{record.myRelationship.data.length}}
of {{record.myRelationship.meta.total}}. 

<button onclick={{loadLink record.myRelationship.links.next}}>
  Load More
</button>

```

You would opt into this by changing from `belongsTo` and `hasMany` to `resource` and `collection` decorators on your classes (or by using a custom record class).

This would allow for incremental migration, and the functional patterns would be made to work with both to make that even easier.

---

<div class="post-metadata">

**Author:** ![ondrejsevcik](https://avatars.discourse-cdn.com/v4/letter/o/ed655f/32.png) [@ondrejsevcik](https://discuss.emberjs.com/u/ondrejsevcik)\
**Post date:** [June 20, 2019, 3:28pm UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/8 "2019-06-20T15:28:43Z")

</div>

But doesn’t that still require from developer to back-trace all the places where the relationship is accessed/used and make sure that on those places is the relationship loaded manually?

I was actually thinking about incremental adoption by using `{async: false}` option on `hasMany`/`belongsTo`, but because of the reason above, it woudn’t be safe for us.

---

<div class="post-metadata">

**Author:** ![runspired](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/runspired/32/18654_2.png) [@runspired](https://discuss.emberjs.com/u/runspired)\
**Post date:** [June 20, 2019, 4:07pm UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/9 "2019-06-20T16:07:03Z")

</div>

@ondrejsevcik You are quite right that migrating directly to a pattern with enforced fetch presents inherit risk, but it’s the same risk that exists during initial development (e.g. enforced peek vs allowed fetch is a similar issue either way).

What the pattern I’m showing does allow for is a migration in which you first keep the existing behavior but with a new pattern and then begin phasing out the locations in which you want to enforce no-fetch. You could write helpers to use this pattern with ember-data-storefront as well to ease migrations there.

So for an existing async relationship:

```nohighlight
{{#each record.myRelationship as |item|}}

{{/each}}

```

Becomes

```nohighlight
{{#let (fetch-relationship-data record.myRelationship) as |list|}}
  {{#each list as |item|}}
      ...
  {{/each}}
{{/let}}

```

and then if you don’t want to allow the fetch

```nohighlight
{{#let (peek-relationship-data record.myRelationship) as |list|}}
  {{#each list as |item|}}
      ...
  {{/each}}
{{/let}}

```

here, `peek` would error if the data were not available locally

---

<div class="post-metadata">

**Author:** ![ondrejsevcik](https://avatars.discourse-cdn.com/v4/letter/o/ed655f/32.png) [@ondrejsevcik](https://discuss.emberjs.com/u/ondrejsevcik)\
**Post date:** [June 24, 2019, 8:04am UTC](https://discuss.emberjs.com/t/what-are-the-benefits-of-async-relationship/16688/10 "2019-06-24T08:04:54Z")

</div>

Thanks for pushing ember-data forward!
