# How Continue Merges Configuration from Multiple Sources: A Deep Dive into the Config System

> Discover how Continue merges configuration from CLI flags, local files, and remote defaults using deterministic rules and deduplication for a unified assistant experience.

- Repository: [Continue/continue](https://github.com/continuedev/continue)
- Tags: deep-dive
- Published: 2026-06-18

---

**Continue combines settings from CLI flags, local files, saved URIs, and remote defaults into a single `AssistantUnrolled` object using deterministic precedence rules, while supporting injected packages and deduplicating overlapping blocks via the `mergeUnrolledAssistants` algorithm.**

Continue is an open-source AI code assistant that supports complex configuration scenarios requiring settings to be composed from multiple origins. Understanding how Continue handles configuration merging from multiple sources is essential for developers customizing models, rules, and environment variables across different deployment contexts.

## Configuration Sources and Precedence Order

The configuration loading process begins in [`extensions/cli/src/configLoader.ts`](https://github.com/continuedev/continue/blob/main/extensions/cli/src/configLoader.ts), where the `loadConfiguration` function determines which source to use based on a strict priority hierarchy. When multiple sources exist, the system selects the highest-priority option and ignores lower-priority alternatives.

The precedence order is:

1. **CLI flag** (`--config`): Specified via `cliConfigPath` parameter
2. **Saved URI**: Stored in authentication config at `~/.continue/config.yaml`
3. **Local config.yaml**: Default path check using `fs.existsSync(defaultConfigPath)`
4. **Remote default config**: Fallback when no local file exists

Each source is loaded through specialized helpers like `loadFromCliFlag`, `loadFromSavedUri`, `loadLocalConfigYaml`, or `loadDefaultConfig`, which eventually invoke `unrollAssistantWithConfig` to resolve the raw configuration into an `AssistantUnrolled` object.

## Injecting Additional Configuration Blocks

Beyond static files, Continue supports dynamic injection of configuration blocks through CLI options. The `ConfigService` class in [`extensions/cli/src/services/ConfigService.ts`](https://github.com/continuedev/continue/blob/main/extensions/cli/src/services/ConfigService.ts) processes "inject blocks" represented as `PackageIdentifier` arrays.

The injection workflow follows three steps:

1. `getAdditionalBlocksFromOptions` extracts injected and additional blocks from CLI arguments
2. `unrollPackageIdentifiersAsConfigYaml` converts package identifiers into a temporary `AssistantUnrolled` containing only the injected blocks
3. `mergeUnrolledAssistants` combines the base configuration with the injected blocks

This approach allows users to augment existing configurations with additional models, MCP servers, or rules without modifying the underlying config files.

## The Configuration Merge Algorithm

All merging logic resides in [`packages/config-yaml/src/load/merge.ts`](https://github.com/continuedev/continue/blob/main/packages/config-yaml/src/load/merge.ts) within the `mergeUnrolledAssistants` function. This implementation handles deep merging of environment variables, request options, and deduplication of configuration blocks.

### Environment and Request Options Merging

The function performs shallow merges for top-level properties:

- **Environment variables**: Combined using spread syntax `{ ...current.env, ...incoming.env }`, where incoming values override existing ones
- **Request options**: Merged via `mergeConfigYamlRequestOptions` to combine HTTP client settings from multiple sources

### Block Deduplication Strategy

For array-based configuration blocks (models, rules, prompts, etc.), the system uses `BlockDuplicationDetector` to ensure uniqueness while preserving precedence:

```ts
const duplicationDetector = new BlockDuplicationDetector();
for (const blockType of BLOCK_TYPES) {
  const allOfType = [...(incoming[blockType] ?? []), ...(current[blockType] ?? [])];
  const deduplicated = [];
  for (const block of allOfType) {
    if (block && !duplicationDetector.isDuplicated(block, blockType)) {
      deduplicated.push(block);
    }
  }
  assistant[blockType] = deduplicated.length ? (deduplicated as any) : undefined;
}

```

The algorithm places incoming blocks before current blocks in the concatenation array, ensuring that injected or higher-priority configurations take precedence when duplicates are detected.

## Finalizing and Persisting Configuration

After merging, `loadConfiguration` persists the source URI to `~/.continue/config.yaml`, enabling subsequent CLI invocations to reuse the same configuration without explicit flags. The `ConfigService` then enriches the merged configuration by adding markdown-derived rules, injecting a default chat model if none is configured, and storing the final `AssistantUnrolled` object in the service container for application-wide access.

## Practical Implementation Examples

### Loading Configuration with CLI Flags and Injection

```ts
import { loadConfiguration } from "./configLoader.js";
import { decodePackageIdentifier } from "@continuedev/config-yaml";

const auth = await loadAuthConfig();
const api = await createApiClient(auth);
const injected = [decodePackageIdentifier("anthropic/claude-sonnet-4-6")];

const { config } = await loadConfiguration(
  auth,
  "./my-config.yaml", // CLI --config flag path
  api,
  injected,
  false,
);
console.log(config.models); // Injected model plus file-defined models

```

### Manual Configuration Merging

```ts
import { mergeUnrolledAssistants } from "@continuedev/config-yaml";

const base = await loadConfigYaml("~/.continue/config.yaml");
const extra = await loadConfigYaml("./extra.yaml");

const merged = mergeUnrolledAssistants(base, extra);
console.log(merged.rules); // Duplicates removed, environments combined

```

## Summary

- **Deterministic precedence**: CLI flags override saved URIs, which override local files, which override remote defaults according to the logic in [`configLoader.ts`](https://github.com/continuedev/continue/blob/main/configLoader.ts)
- **Injection support**: Package identifiers are converted to temporary configs and merged with base configurations using `mergeUnrolledAssistants`
- **Intelligent deduplication**: `BlockDuplicationDetector` ensures identical blocks from different sources appear only once, with incoming blocks taking precedence over existing ones
- **Shallow merging**: Environment variables and request options use simple object spreads, with later values overriding earlier ones
- **Persistence**: Selected configuration sources are saved to `~/.continue/config.yaml` for subsequent CLI sessions

## Frequently Asked Questions

### What happens if I specify both a CLI config flag and a local config.yaml?

The CLI flag takes precedence. In [`configLoader.ts`](https://github.com/continuedev/continue/blob/main/configLoader.ts), the system checks `if (cliConfigPath) return { type: "cli-flag", path: cliConfigPath }` before evaluating local files, ensuring explicit command-line arguments always win over disk-based configurations.

### How does Continue handle duplicate model definitions from different sources?

The `BlockDuplicationDetector` class in [`merge.ts`](https://github.com/continuedev/continue/blob/main/merge.ts) identifies duplicate blocks by type and content. When the same model appears in both injected packages and local configuration, the injected version appears first in the merged array and the duplicate is removed, giving priority to the injected definition according to the concatenation order `[...incoming, ...current]`.

### Can environment variables from multiple configs be combined?

Yes. The merge algorithm uses object spreading `{ ...current.env, ...incoming.env }` to shallow merge environment variables. If the same variable exists in both configurations, the incoming value overrides the current value, following standard JavaScript object merge behavior.

### Where does Continue store the last used configuration source?

After loading, `loadConfiguration` persists the source URI to `~/.continue/config.yaml`. This saved URI serves as the second-highest priority source in subsequent CLI runs, allowing the system to remember your preferred configuration between sessions without requiring the `--config` flag every time.