# Cordis HMR Full Reload vs Partial Reload: Understanding the Difference

> Understand the difference between Cordis HMR full reload and partial reload. Learn when to use each to optimize your development workflow and avoid unnecessary restarts.

- Repository: [Cordiverse/cordis](https://github.com/cordiverse/cordis)
- Tags: deep-dive
- Published: 2026-08-23

---

**Full reload restarts the entire Cordis process when external dependencies change, while partial reload only re-initializes specific plugins that explicitly accept hot updates via `ctx.plugin.hot.accept()`.**

Cordis HMR (Hot Module Replacement) provides two distinct reload strategies to balance development speed against application stability. Understanding when Cordis performs a full reload versus a partial reload helps developers optimize their plugin architecture for faster iteration cycles. This article examines the implementation details in the `cordiverse/cordis` repository to explain how the HMR service decides which strategy to apply.

## How Cordis HMR Decides Between Full and Partial Reloads

The HMR service maintains three critical sets to determine the reload strategy: `externals`, `accepted`, and `declined`. In [`packages/hmr/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/src/index.ts) (lines 58-74), the service initializes these tracking sets to categorize file changes as they occur. When a file change is detected, the watcher first checks if the modified file belongs to the `externals` set, which represents the dependency tree of the CLI worker entry point.

If the file is external, the service emits a full-process restart. Otherwise, the change enters the `stashed` set for dependency graph resolution. During the next tick (lines 112-124), the service resolves which files are accepted by plugins and emits a partial reload event containing only the affected modules.

## Full Reload: When the Entire Process Restarts

A **full reload** occurs when changes affect files outside the project's explicitly managed source tree. This includes modifications to `node_modules` or any file not accepted by a plugin's HMR contract. When the HMR service detects a change in the `externals` set, it triggers an `hmr/reload` event with a flag indicating a full process restart.

This strategy serves as the safest fallback when a change could unpredictably affect module resolution or break the running environment. All plugins re-initialize, and the application state rebuilds from scratch, ensuring consistency at the cost of startup time.

## Partial Reload: Granular Plugin Updates

**Partial reload** enables fine-grained updates without tearing down the entire application. Plugins opt into this behavior by calling `ctx.plugin.hot.accept()` in their initialization code. When a file change affects an accepted module, the HMR service (in [`packages/hmr/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/src/index.ts)) emits an `hmr/reload` event containing a `Map<Plugin, Reload>` that specifies exactly which plugins need re-initialization.

This approach preserves the state of unaffected plugins while only reloading the changed code. Plugins can also decline updates using `ctx.plugin.hot.decline()`, adding files to the `declined` set to prevent them from triggering any reload.

## Implementing Hot Acceptance in Plugins

To enable partial reloads for your plugin, register an acceptance handler using the Context API provided in [`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts):

```typescript
export default function myPlugin(ctx: Context) {
  ctx.plugin('my-plugin', async (ctx) => {
    // Plugin initialization logic
  });

  // Enable partial reload support
  ctx.plugin.hot.accept(async (mod) => {
    // `mod` contains the updated module
    await ctx.refresh();
  });
}

```

To explicitly prevent a file from triggering reloads:

```typescript
ctx.plugin.hot.decline(() => {
  // This file will not trigger HMR updates
});

```

## Listening to HMR Events

The Cordis HMR system emits lifecycle events that plugins can monitor. The `hmr/reload` event provides details about which plugins were affected:

```typescript
ctx.on('hmr/reload', (reloads: Map<Plugin, Reload>) => {
  for (const [plugin, info] of reloads) {
    console.log(`Plugin ${plugin.name} reloaded ${info.filename}`);
  }
});

```

This event receives different payloads depending on the reload type. For partial reloads, it contains the specific plugin map. For full reloads, the flag indicates a complete process restart is imminent.

## Summary

- **Full reload** restarts the entire Cordis process when external dependencies or non-accepted files change, ensuring complete state consistency.
- **Partial reload** reinitializes only specific plugins that have called `ctx.plugin.hot.accept()`, preserving application state and providing faster iteration.
- The decision logic resides in [`packages/hmr/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/src/index.ts), which maintains `externals`, `accepted`, and `declined` sets to categorize file changes.
- Plugins control their reload behavior through the Context API using `hot.accept()` and `hot.decline()` methods.

## Frequently Asked Questions

### What triggers a full reload in Cordis HMR?

A full reload triggers when modified files belong to the `externals` set, which includes the CLI worker's dependency tree and any files outside explicitly accepted modules. Changes in `node_modules` or files not covered by `ctx.plugin.hot.accept()` automatically force a complete process restart to ensure module resolution integrity.

### How do I make my plugin support partial reloads?

Call `ctx.plugin.hot.accept()` during your plugin initialization, passing a callback that handles the updated module. This registers your plugin in the `accepted` set tracked by the HMR service in [`packages/hmr/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/src/index.ts). Without this explicit opt-in, your plugin dependencies default to the `externals` set, triggering full reloads on change.

### Can I prevent a specific file change from triggering any reload?

Yes. Use `ctx.plugin.hot.decline()` to add files to the `declined` set. When the HMR service detects changes in declined files, it ignores them entirely, preventing both full and partial reloads. This is useful for configuration files or assets that reload independently of the Cordis plugin system.

### Where is the HMR logic implemented in the Cordis source code?

The core HMR implementation lives in [`packages/hmr/src/index.ts`](https://github.com/cordiverse/cordis/blob/main/packages/hmr/src/index.ts), which defines the watcher logic, set management (lines 58-74), and reload resolution (lines 112-124). The Context API methods (`hot.accept` and `hot.decline`) are exposed through [`packages/core/src/context.ts`](https://github.com/cordiverse/cordis/blob/main/packages/core/src/context.ts), while module resolution relies on [`packages/loader/src/internal.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/internal.ts).