Ember Data Part 3: Doing It Ourselves

This is a follow-up to Ember Data Origins: Drafting on Rails and Going Off The Rails.


ember-data-model-fragments lets Ember apps embed nested JSON objects inside models - a pattern Ember Data has never natively supported. Hundreds of apps depend on it. When ember-data 4.12 rewrote its cache internals, model-fragments broke, and there was no clear upgrade path.

In Part 2, I wrote about the promises made to the model-fragments community. The April 2023 blog post committed to "extensive time to assist in adding support for 4.12." A GitHub issue laid out a detailed roadmap, promising "I'll be working with @RSG and anyone else interested to achieve this."

None of it happened. The roadmap sat abandoned. Teams stayed stuck on 4.6.

So I did it myself.


The Problem

ember-data 4.12 introduced a fundamental architectural change: the V2 Cache. The old per-resource RecordData pattern that model-fragments depended on was deprecated in 4.7 and gone by 4.12. Every hook the addon used to manage fragment state had been reworked.

This wasn't a minor version bump. It was a rewrite of the internals that made fragments possible.

Old API New API
RecordData (per-resource) Cache (singleton)
pushData() upsert()
sync() patch()
notifyPropertyChange notifyChange(identifier, namespace, key)

The Ember Data team knew this would break model-fragments. They promised to help. They didn't.


The Work

I spent weeks on the PR. The core changes:

  • Created FragmentCache that wraps JSONAPICache and implements the V2 Cache interface
  • Created FragmentStateManager for managing fragment-specific state keyed by StableRecordIdentifier
  • Created FragmentRecordDataProxy for backwards compatibility with code expecting the per-resource API
  • Updated the Store extension to use createCache() instead of createRecordDataFor()
  • Updated all attribute decorators, array classes, and transforms to work with identifier-based cache access
  • Fixed fragment destruction handling for ember-data 4.12's disconnected state behavior

The hardest part was fragment destruction. In the old API, a fragment's lifecycle was tied to its parent record. In 4.12, the cache can disconnect records independently, so fragments could be orphaned mid-teardown. Getting the ordering right meant tracing through ember-data's internal state machine with minimal documentation - the V2 Cache interface is specified, but the interaction between willCommit, didCommit, and unloadRecord for nested resources is not.

182 tests. CI running against ember-data 4.12, Ember LTS 5.8, 5.12, release, beta, and canary. Embroider-safe and embroider-optimized scenarios.


The Community Shows Up

I posted the PR and asked for validation:

I'm letting this bake as we ready our app for 4.12 - I'd like to be sure this is correct before merging. We have a lot of test failures, but they seem more related to 4.12 than fragments. If any other teams using model-fragments want to help validate this upgrade path it would be great!

Within a week, @whatthewhat tested it against their large Ember 4.12.8 app (156 model files with fragments) and found four compatibility issues I'd missed due to silenced deprecations in my own app's workflow. They provided a detailed writeup with fixes for each:

  1. normalizeModelName removed from ember-data - replace with dasherize
  2. reopenClass deprecated - needs deprecation workflow entry (saving full fix for 5.x)
  3. Schema access without store.modelFor() deprecated - updated copy() and setFragmentOwner()
  4. ember-compatibility-helpers needed updating for ember-cli-babel 8.x

I applied three of the four. The reopenClass deprecation I left as-is, with a note for apps to silence it. Unlike Ember Data's philosophy, I'd rather not introduce breaking changes mid-cycle. The full EmberObject removal can happen as part of 5.x support.

This is what open source collaboration looks like. Someone does the initial work, others validate it against their use cases, issues get found and fixed, and everyone benefits. No corporate roadmaps required.


The Result

ember-data-model-fragments v7.0.1 supports ember-data 4.12+.

Ember Data Model Fragments Node.JS
>= v3.28.x < v4.7.x v6.x 14+
v4.7.x - v4.11.x untested -
>= v4.12.x v7.x 18+

Teams that have been stuck on 4.6 for years can finally upgrade. Not because the Ember Data team delivered on their promises, but because the community did the work itself.


The Lesson

The Ember Data team had every opportunity to help. They wrote blog posts. They posted GitHub issues with detailed plans. They made promises. And then priorities shifted. That's frustrating, but it's how open source works - maintainers have limited time and competing demands.

The takeaway isn't resentment. It's that promises aren't a plan. If your team depends on a library, waiting for someone else to fix it is a risk. The community is the only thing you can rely on.


The Clock Is Ticking

This buys time. It doesn't solve the problem.

The 5.4+ series introduces SchemaRecord and further architectural changes. The hooks model-fragments depends on are being reworked again. I've spiked out what 5.x support would look like, and it's another significant rewrite. The EmberObject removal alone touches nearly every file.

There may be a 4.13 release as well. It's a non-LTS version, but it removes EmberObject and clears out multiple other deprecations, which should help with modern build tooling. For teams who want to clean up deprecations without jumping to 5.x, that could be a useful stepping stone.

At some point, the cost of keeping up with Ember Data's churn exceeds the value of the library. Model-fragments will likely not survive the 5.x series. Teams using it need to start planning their exit strategy: migrate to SchemaRecord (if it ever stabilizes), flatten their data structures, or move off Ember Data entirely.

This release gives those teams runway. Use it wisely.


Thanks to @whatthewhat for the testing and detailed feedback, and to @RobbieTheWagner for the review.

Comments

Leave a Comment

Used for confirmation only. Not displayed publicly.