From 931e14872fafb4f519360c0a9ca0ab7ab1db773e Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Wed, 2 Jul 2025 23:52:14 -0400
Subject: [PATCH 1/6] Deprecate initializers
---
text/9999-deprecate-initializers.md | 329 ++++++++++++++++++++++++++++
1 file changed, 329 insertions(+)
create mode 100644 text/9999-deprecate-initializers.md
diff --git a/text/9999-deprecate-initializers.md b/text/9999-deprecate-initializers.md
new file mode 100644
index 0000000000..7690d6cbf4
--- /dev/null
+++ b/text/9999-deprecate-initializers.md
@@ -0,0 +1,329 @@
+---
+stage: accepted
+start-date:
+release-date:
+release-versions:
+teams: # delete teams that aren't relevant
+ - framework
+ - learning
+prs:
+ accepted: # update this to the PR that you propose your RFC in
+project-link:
+---
+
+
+
+<-- Replace "RFC title" with the title of your RFC -->
+# Deprecate Application Initializers and Instance Initializers
+
+## Summary
+
+This RFC proposes deprecating Ember's application initializers and instance initializers in favor of explicit application lifecycle management. The current initializer system will be replaced with direct access to application and instance objects during the boot process, enabling async/await support and providing more explicit control over application setup.
+
+## Motivation
+
+The current initializer system has several limitations that make it difficult to work with in modern JavaScript environments:
+
+1. **No async/await support**: Initializers cannot be awaited, making asynchronous setup operations difficult to coordinate and debug.
+
+2. **Implicit execution order**: The `before` and `after` properties create implicit dependencies that are hard to reason about and can lead to subtle ordering bugs.
+
+3. **Hidden lifecycle**: The automatic execution of initializers makes the application boot process opaque and harder to debug.
+
+4. **Limited access to application state**: Initializers receive only the application or instance object, without access to other important lifecycle information.
+
+5. **Testing complexity**: The automatic execution of initializers during testing requires complex workarounds to avoid side effects.
+
+The replacement functionality provides explicit control over the application lifecycle by allowing developers to write setup code directly in their application entry point, with full access to modern JavaScript async/await patterns.
+
+## Transition Path
+
+### Current Initializer Usage Patterns
+
+Application initializers are currently defined in `app/initializers/` and run during application boot:
+
+```js
+// app/initializers/session.js
+export default {
+ name: 'session',
+ initialize(application) {
+ application.inject('route', 'session', 'service:session');
+ }
+};
+```
+
+Instance initializers are defined in `app/instance-initializers/` and run during instance creation:
+
+```js
+// app/instance-initializers/current-user.js
+export default {
+ name: 'current-user',
+ initialize(applicationInstance) {
+ let session = applicationInstance.lookup('service:session');
+ return session.loadCurrentUser();
+ }
+};
+```
+
+### New Explicit Lifecycle Pattern
+
+This would replace the contents of the script tag in the existing `@ember/app-blueprint`:
+```html
+
+```
+
+However! We will not change the default from the above, as the simple case is the most common.
+
+> [!IMPORTANT]
+> The above 3 line entrypoint for ember applications will remain the default. This RFC is primarily about updates to documentation showing how we can achieve a new way of "initializers" while also slimming the default experience for new projects.
+
+The new pattern provides explicit control over application lifecycle in the main application entry point:
+
+```js
+import Application from '#app/app.ts';
+import environment from '#app/config.ts';
+
+let app = Application.create({
+ ...environment.APP,
+ autoboot: false,
+});
+
+// anything running here with access to `app`
+// is equivelent to classic "initializers"
+//
+// These can be awaited, which was not possible before
+console.log(app);
+
+await app.boot();
+let instance = await app.buildInstance();
+await instance.boot();
+await instance.visit('/');
+
+// anything running here with access to `instance`
+// is equivelent to classic "instance initializers"
+//
+// These can be awaited, which was not possible before
+console.log(instance);
+```
+
+### Migration Steps for Common Use Cases
+
+#### 1. Service Registration
+
+**Before:**
+```js
+// app/initializers/register-websocket.js
+export default {
+ name: 'register-websocket',
+ initialize(application) {
+ application.register('service:websocket', WebSocketService);
+ }
+};
+```
+
+**After:**
+```js
+// In main.js or index.html
+let app = Application.create({ ...environment.APP, autoboot: false });
+
+app.register('service:websocket', WebSocketService);
+
+await app.boot();
+// ... rest of boot process
+```
+
+#### 2. Asynchronous Setup
+
+**Before (not possible):**
+```js
+// app/initializers/async-setup.js
+export default {
+ name: 'async-setup',
+ initialize(application) {
+ // Cannot await here - initializers don't support async
+ fetchConfigFromServer().then(config => {
+ application.register('config:remote', config);
+ });
+ }
+};
+```
+
+**After:**
+```js
+// In main.js or index.html
+let app = Application.create({ ...environment.APP, autoboot: false });
+
+// Now we can await asynchronous setup
+let config = await fetchConfigFromServer();
+
+await app.boot();
+// ... rest of boot process
+```
+
+#### 3. Instance-level Setup
+
+**Before:**
+```js
+// app/instance-initializers/load-user.js
+export default {
+ name: 'load-user',
+ initialize(applicationInstance) {
+ let session = applicationInstance.lookup('service:session');
+ return session.loadCurrentUser();
+ }
+};
+```
+
+**After:**
+```js
+// In main.js or index.html
+let app = Application.create({ ...environment.APP, autoboot: false });
+await app.boot();
+let instance = await app.buildInstance();
+
+// Instance-level setup with full async/await support
+let session = instance.lookup('service:session');
+await session.loadCurrentUser();
+
+await instance.boot();
+await instance.visit('/');
+```
+
+### Deprecation Timeline
+
+1. **Phase 1**: Emit deprecation warnings when initializers are detected
+2. **Phase 2**: Update Ember CLI blueprints to generate the new pattern
+3. **Phase 3**: Remove support for automatic initializer discovery and execution
+4. **Phase 4**: Remove initializer-related APIs
+
+### Ecosystem Implications
+
+- **ember-load-initializers**: This addon will be deprecated as initializer discovery will no longer be needed
+- **Lint rules**: eslint-plugin-ember should add rules to detect deprecated initializer patterns
+- **Blueprints**: Ember CLI blueprints should be updated to generate the new explicit pattern
+- **Addon ecosystem**: Addons that provide initializers will need to document the migration path
+- **Testing**: Test helpers that skip initializers can be simplified or removed
+
+## How We Teach This
+
+This change represents a significant shift in how Ember applications are structured, requiring updates across multiple learning resources:
+
+### Guides Updates
+
+The "Applications and Instances" section of the guides will need to be rewritten to:
+- Remove documentation for initializers and instance initializers
+- Add comprehensive documentation for explicit application lifecycle management
+- Provide migration examples for common initializer patterns
+- Explain the benefits of explicit control and async/await support
+
+### API Documentation
+
+- Mark initializer-related APIs as deprecated
+- Document the new explicit lifecycle pattern
+- Provide clear examples of the migration path
+
+### Tutorial Updates
+
+New user tutorials should:
+- Show the explicit lifecycle pattern from the beginning
+- Avoid teaching the deprecated initializer concept
+- Emphasize the benefits of explicit control and modern JavaScript patterns
+
+### Blog Posts and Communication
+
+- Publish a detailed blog post explaining the motivation and migration path
+- Create video content showing the migration process
+- Update conference talk materials to reflect the new patterns
+
+## Drawbacks
+
+### Learning Curve
+
+- Existing Ember developers will need to learn the new explicit pattern
+- The new pattern requires understanding of application lifecycle concepts that were previously hidden
+
+### Migration Effort
+
+- Large applications with many initializers will require significant migration effort
+- Addon authors will need to update their libraries and documentation
+
+### Code Duplication
+
+- Some boilerplate code that was previously hidden in the initializer system will now be explicit in each application
+
+### Ecosystem Fragmentation
+
+- During the transition period, there will be two different patterns in use across the ecosystem
+- Documentation and examples will need to cover both patterns temporarily
+
+## Alternatives
+
+### Option 1: Async Initializer Support
+
+Instead of deprecating initializers, we could add async/await support to the existing system:
+
+```js
+// app/initializers/async-setup.js
+export default {
+ name: 'async-setup',
+ async initialize(application) {
+ let config = await fetchConfigFromServer();
+ application.register('config:remote', config);
+ }
+};
+```
+
+**Pros**: Maintains existing patterns while adding modern async support
+**Cons**: Still maintains the implicit ordering and hidden lifecycle issues
+
+### Option 2: Explicit Initializer Registration
+
+Keep the initializer concept but require explicit registration:
+
+```js
+// In main.js
+import sessionInitializer from './initializers/session';
+import userInitializer from './instance-initializers/user';
+
+let app = Application.create({ ...environment.APP, autoboot: false });
+app.registerInitializer(sessionInitializer);
+app.registerInstanceInitializer(userInitializer);
+```
+
+**Pros**: Maintains some backwards compatibility while providing explicit control
+**Cons**: Still maintains the complexity of the initializer system
+
+### Option 3: Do Nothing
+
+Continue with the current initializer system.
+
+**Pros**: No migration effort required
+**Cons**: Continues to limit developers from using modern JavaScript patterns and maintains the current complexity and debugging difficulties
+
+## Unresolved questions
+
+1. **Timing**: What is the exact timeline for each phase of the deprecation?
+
+2. **Addon Migration**: How should popular addons that rely heavily on initializers (like ember-simple-auth) handle the migration?
+
+3. **Development Tools**: Should Ember Inspector be updated to show the explicit lifecycle steps instead of initializer execution?
+
+4. **Testing Patterns**: What testing patterns should be recommended for the new explicit lifecycle approach?
+
+5. **Error Handling**: How should errors in the explicit setup code be handled and reported compared to the current initializer error handling?
From c53d12ae212234624f216e557024eb46773e7609 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 3 Jul 2025 00:15:02 -0400
Subject: [PATCH 2/6] Update meta
---
...recate-initializers.md => 1120-deprecate-initializers.md} | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
rename text/{9999-deprecate-initializers.md => 1120-deprecate-initializers.md} (98%)
diff --git a/text/9999-deprecate-initializers.md b/text/1120-deprecate-initializers.md
similarity index 98%
rename from text/9999-deprecate-initializers.md
rename to text/1120-deprecate-initializers.md
index 7690d6cbf4..abf78228cd 100644
--- a/text/9999-deprecate-initializers.md
+++ b/text/1120-deprecate-initializers.md
@@ -1,13 +1,13 @@
---
stage: accepted
-start-date:
+start-date: 2025-07-02T00:00:00.000Z # In format YYYY-MM-DDT00:00:00.000Z
release-date:
release-versions:
teams: # delete teams that aren't relevant
- framework
- learning
prs:
- accepted: # update this to the PR that you propose your RFC in
+ accepted: https://github.com/emberjs/rfcs/pull/1120
project-link:
---
@@ -24,7 +24,6 @@ prs:
project-link: Leave as is
-->
-<-- Replace "RFC title" with the title of your RFC -->
# Deprecate Application Initializers and Instance Initializers
## Summary
From 93ac1acecaf18c9fb71b599d5560af3d26cb29b5 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 3 Jul 2025 00:27:21 -0400
Subject: [PATCH 3/6] Details, and some manual stuff
---
text/1120-deprecate-initializers.md | 127 ++++++++++++----------------
1 file changed, 53 insertions(+), 74 deletions(-)
diff --git a/text/1120-deprecate-initializers.md b/text/1120-deprecate-initializers.md
index abf78228cd..57937d8496 100644
--- a/text/1120-deprecate-initializers.md
+++ b/text/1120-deprecate-initializers.md
@@ -30,6 +30,9 @@ project-link: Leave as is
This RFC proposes deprecating Ember's application initializers and instance initializers in favor of explicit application lifecycle management. The current initializer system will be replaced with direct access to application and instance objects during the boot process, enabling async/await support and providing more explicit control over application setup.
+> [!NOTE]
+> This RFC assumes usage of the v2 app blueprint, via `@ember/app-blueprint`
+
## Motivation
The current initializer system has several limitations that make it difficult to work with in modern JavaScript environments:
@@ -121,6 +124,42 @@ await instance.visit('/');
console.log(instance);
```
+### To share initialization with tests
+
+Developers can extract the contents of the script tag to a `boot.ts` or `boot.js`, with the same contents.
+
+> [!DANGER]
+> Since initializers would no longer be tied to the application instance itself, initializers would not normally run during tests.
+
+To have initializers run during tests, a developer would want to edit their in-test-copy of `setupApplicationTest` to run the initializers there, for example:
+
+```ts
+function setupApplicationTest(hooks: NestedHooks, options?: SetupTestOptions) {
+ upstreamSetupApplicationTest(hooks, options);
+
+ hooks.beforeEach(function () {
+ let instance = this.owner;
+ runInstanceInitializer(instance)
+ });
+
+ // Additional setup for application tests can be done here.
+ //
+ // For example, if you need an authenticated session for each
+ // application test, you could do:
+ //
+ // hooks.beforeEach(async function () {
+ // await authenticateSession(); // ember-simple-auth
+ // });
+ //
+ // This is also a good place to call test setup functions coming
+ // from other addons:
+ //
+ // setupIntl(hooks, 'en-us'); // ember-intl
+ // setupMirage(hooks); // ember-cli-mirage
+}
+```
+
+
### Migration Steps for Common Use Cases
#### 1. Service Registration
@@ -204,20 +243,11 @@ await instance.boot();
await instance.visit('/');
```
-### Deprecation Timeline
-
-1. **Phase 1**: Emit deprecation warnings when initializers are detected
-2. **Phase 2**: Update Ember CLI blueprints to generate the new pattern
-3. **Phase 3**: Remove support for automatic initializer discovery and execution
-4. **Phase 4**: Remove initializer-related APIs
-
### Ecosystem Implications
-- **ember-load-initializers**: This addon will be deprecated as initializer discovery will no longer be needed
-- **Lint rules**: eslint-plugin-ember should add rules to detect deprecated initializer patterns
-- **Blueprints**: Ember CLI blueprints should be updated to generate the new explicit pattern
-- **Addon ecosystem**: Addons that provide initializers will need to document the migration path
-- **Testing**: Test helpers that skip initializers can be simplified or removed
+- **ember-load-initializers**: This addon will be README-deprecated as initializer discovery will no longer be needed -- the README will show the new way to run initializers if they are needed.
+- **Blueprints**: Ember CLI blueprints should be updated to remove use of initializers
+- **Addon ecosystem**: Addons that provide initializers will need to document the migration path -- which is to import the initializer from the addon, and place it in the script tag in the appropriate place.
## How We Teach This
@@ -228,70 +258,22 @@ This change represents a significant shift in how Ember applications are structu
The "Applications and Instances" section of the guides will need to be rewritten to:
- Remove documentation for initializers and instance initializers
- Add comprehensive documentation for explicit application lifecycle management
+ - this is needed anyway because it's not described anywhere
- Provide migration examples for common initializer patterns
- Explain the benefits of explicit control and async/await support
### API Documentation
- Mark initializer-related APIs as deprecated
-- Document the new explicit lifecycle pattern
-- Provide clear examples of the migration path
-
-### Tutorial Updates
-
-New user tutorials should:
-- Show the explicit lifecycle pattern from the beginning
-- Avoid teaching the deprecated initializer concept
-- Emphasize the benefits of explicit control and modern JavaScript patterns
-
-### Blog Posts and Communication
-
-- Publish a detailed blog post explaining the motivation and migration path
-- Create video content showing the migration process
-- Update conference talk materials to reflect the new patterns
## Drawbacks
-### Learning Curve
-
-- Existing Ember developers will need to learn the new explicit pattern
-- The new pattern requires understanding of application lifecycle concepts that were previously hidden
-
-### Migration Effort
-
-- Large applications with many initializers will require significant migration effort
-- Addon authors will need to update their libraries and documentation
-
-### Code Duplication
-
-- Some boilerplate code that was previously hidden in the initializer system will now be explicit in each application
-
-### Ecosystem Fragmentation
-
-- During the transition period, there will be two different patterns in use across the ecosystem
-- Documentation and examples will need to cover both patterns temporarily
+- Large applications with many initializers will require a little migration effort
+- Addon authors will need to update their libraries and documentation -- initializers from addons would no longer run automatically
## Alternatives
-### Option 1: Async Initializer Support
-
-Instead of deprecating initializers, we could add async/await support to the existing system:
-
-```js
-// app/initializers/async-setup.js
-export default {
- name: 'async-setup',
- async initialize(application) {
- let config = await fetchConfigFromServer();
- application.register('config:remote', config);
- }
-};
-```
-
-**Pros**: Maintains existing patterns while adding modern async support
-**Cons**: Still maintains the implicit ordering and hidden lifecycle issues
-
-### Option 2: Explicit Initializer Registration
+### Option 1: Explicit Initializer Registration
Keep the initializer concept but require explicit registration:
@@ -305,10 +287,10 @@ app.registerInitializer(sessionInitializer);
app.registerInstanceInitializer(userInitializer);
```
-**Pros**: Maintains some backwards compatibility while providing explicit control
-**Cons**: Still maintains the complexity of the initializer system
+**Pros**: This is the closest to the existing behavior with the least amount of boilerplate.
+**Cons**: Still maintains the complexity of the initializer system, and folks that don't use it will still have to pay for its existence.
-### Option 3: Do Nothing
+### Option 2: Do Nothing
Continue with the current initializer system.
@@ -317,12 +299,9 @@ Continue with the current initializer system.
## Unresolved questions
-1. **Timing**: What is the exact timeline for each phase of the deprecation?
-
-2. **Addon Migration**: How should popular addons that rely heavily on initializers (like ember-simple-auth) handle the migration?
-
-3. **Development Tools**: Should Ember Inspector be updated to show the explicit lifecycle steps instead of initializer execution?
+n/a
-4. **Testing Patterns**: What testing patterns should be recommended for the new explicit lifecycle approach?
+## References
-5. **Error Handling**: How should errors in the explicit setup code be handled and reported compared to the current initializer error handling?
+- async initializers were first asked about in [2013](https://discuss.emberjs.com/t/initializers-that-return-promises/2782) (maybe earlier?)
+- previous RFC was attempted, [RFC#572](https://github.com/emberjs/rfcs/pull/572)
From 3631868e4e03172e3ee69970160f7880742fa289 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 3 Jul 2025 00:33:08 -0400
Subject: [PATCH 4/6] Add link to demo app
---
text/1120-deprecate-initializers.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/text/1120-deprecate-initializers.md b/text/1120-deprecate-initializers.md
index 57937d8496..bcc9b50b60 100644
--- a/text/1120-deprecate-initializers.md
+++ b/text/1120-deprecate-initializers.md
@@ -33,6 +33,8 @@ This RFC proposes deprecating Ember's application initializers and instance init
> [!NOTE]
> This RFC assumes usage of the v2 app blueprint, via `@ember/app-blueprint`
+[Here is a demo app](https://github.com/NullVoxPopuli/ember-initializers-demo/commit/f57e30c0cee5e83794fa71961a8d091ededaf292)
+
## Motivation
The current initializer system has several limitations that make it difficult to work with in modern JavaScript environments:
From 51b94f43757a0b9cdb6b76184eda4ca3bbf18071 Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 3 Jul 2025 00:33:36 -0400
Subject: [PATCH 5/6] Remove point that didn't make sense
---
text/1120-deprecate-initializers.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/text/1120-deprecate-initializers.md b/text/1120-deprecate-initializers.md
index bcc9b50b60..5f7984904a 100644
--- a/text/1120-deprecate-initializers.md
+++ b/text/1120-deprecate-initializers.md
@@ -47,8 +47,6 @@ The current initializer system has several limitations that make it difficult to
4. **Limited access to application state**: Initializers receive only the application or instance object, without access to other important lifecycle information.
-5. **Testing complexity**: The automatic execution of initializers during testing requires complex workarounds to avoid side effects.
-
The replacement functionality provides explicit control over the application lifecycle by allowing developers to write setup code directly in their application entry point, with full access to modern JavaScript async/await patterns.
## Transition Path
From fbfc1b4ec084f2d252da74696649872def57375f Mon Sep 17 00:00:00 2001
From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Date: Thu, 3 Jul 2025 07:19:01 -0400
Subject: [PATCH 6/6] clarify this is all index.html
---
text/1120-deprecate-initializers.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/text/1120-deprecate-initializers.md b/text/1120-deprecate-initializers.md
index 5f7984904a..6eac96cdde 100644
--- a/text/1120-deprecate-initializers.md
+++ b/text/1120-deprecate-initializers.md
@@ -80,7 +80,7 @@ export default {
### New Explicit Lifecycle Pattern
-This would replace the contents of the script tag in the existing `@ember/app-blueprint`:
+This would replace the contents of the script tag in the existing `@ember/app-blueprint`'s index.html:
```html