# Codex config.toml: Profiles, Project Config, Precedence

> How Codex config.toml layers work: user, profile, project and CLI settings, which one wins, what projects cannot set, and a safe setup for a team repo.

Canonical: https://bridge-terminal.com/atlas/blog/codex-config-toml-profiles-project-precedence/
Last updated: 2026-11-01

Published 1 November 2026 · Technical · How-to · 5 min read

## The short version

- Codex reads settings from several layers. From highest to lowest: CLI flags, project files, the selected profile, your user file, cloud-managed defaults, system config, built-in defaults.
- A profile is its own file, ~/.codex/<name>.config.toml, with top-level keys. From Codex 0.134.0 the old [profiles.name] table and the profile = selector are no longer supported.
- A repo can ship .codex/config.toml, but Codex loads it only when the project is trusted, and it ignores provider, notification and telemetry keys set there.
- Use -c or --config for one-off overrides, and keep shared defaults in config.toml so profiles hold only what differs.

Codex reads its settings from more than one place, and the place that wins is not always the one you edited last. The short rule: command-line flags beat project files, project files beat a profile you select, a profile beats your personal `~/.codex/config.toml`, and everything else is a default. This guide shows how to set up each layer so a team repo behaves the same for everyone and a one-off run does not need a file edit.

Everything below comes from OpenAI's Codex configuration docs. Where the docs do not say something, this article does not either.

## Where does Codex read its configuration from?

These are the layers you can meet:

- **User config:** `~/.codex/config.toml`. Your personal defaults.
- **Project config:** a `.codex/config.toml` inside a repo or subfolder. It scopes settings to that project.
- **Profile files:** `~/.codex/<profile-name>.config.toml`, picked with `--profile`.
- **System config:** `/etc/codex/config.toml` on Unix.
- **Cloud-managed defaults:** a `config.toml` delivered for the signed-in workspace, when one exists.

Managed-device and workspace requirements exist as well. The configuration docs only point to a separate managed-configuration page for them, so check that page if your organization enforces settings.

## Which setting wins? The precedence order

From highest to lowest:

1. CLI flags and `--config` overrides
2. Project config files, from the project root down to the current directory (closest wins; trusted projects only)
3. The profile file chosen with `--profile`
4. User config (`~/.codex/config.toml`)
5. Cloud-managed `config.toml` defaults, when delivered for the signed-in workspace
6. System config (`/etc/codex/config.toml` on Unix)
7. Built-in defaults

Two consequences are easy to miss. First, a project file overrides a profile. If your profile sets `model` and the repo's `.codex/config.toml` also sets it, the repo wins. Second, there is one documented exception: for `model_catalog_json`, when both a profile and the project set it, Codex uses the profile value.

## The four keys most teams set first

The docs show these as the basic block:

```toml
model = "gpt-6.1-sol"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
model_reasoning_effort = "medium"
```

What they do, and what values the reference page allows:

- `model` sets the default model. The docs say to pick one available to your signed-in account or workspace, and use `gpt-6.1-sol` only as an example. Check which models you actually have.
- `approval_policy` controls when Codex pauses to ask before running commands. Allowed values are `on-request`, `never`, or a `granular` table. The reference says `untrusted` is no longer supported and `on-failure` is deprecated; use `on-request` for interactive runs or `never` for non-interactive ones. Old configs that use the retired values need updating.
- `sandbox_mode` is `read-only`, `workspace-write` or `danger-full-access`. It sets filesystem and network access while commands run.
- `model_reasoning_effort` sets reasoning effort when the model supports it. The docs list low, medium, high, xhigh, max and ultra as examples and say the available levels depend on the model and client. Do not assume every model accepts every level.

## How do Codex profiles work now?

A profile is a separate file. `--profile deep-review` loads `~/.codex/config.toml` first, then overlays `~/.codex/deep-review.config.toml` on top.

Rules from the docs:

- Names can use letters, numbers, hyphens and underscores.
- Use top-level keys in the profile file. Do not nest them under `[profiles.deep-review]`.
- Keep shared defaults in `config.toml` and use profiles only for values that differ.

An example profile for careful reviews:

```toml
# ~/.codex/deep-review.config.toml
model = "gpt-6.1-sol"
model_reasoning_effort = "medium"
approval_policy = "on-request"
model_catalog_json = "/Users/me/.codex/model-catalogs/deep-review.json"
```

Use it with the interactive command:

```sh
codex --profile deep-review
```

The profile mechanism is the same for any Codex run, so it gives you a simple way to keep different defaults for different jobs, such as careful review versus quick edits, without separate scripts.

### Migrating old profiles (Codex 0.134.0 and later)

This is the change most likely to bite. From 0.134.0, `--profile` no longer reads `[profiles.profile-name]` tables from `config.toml`, and the top-level `profile = "profile-name"` selector is no longer supported. To migrate:

1. Create `~/.codex/profile-name.config.toml`.
2. Move the keys from the old table into it as top-level keys.
3. Remove the old table and the selector from `config.toml`.

If a profile seems to have no effect after an upgrade, check for the old format first. The docs do not describe what Codex prints in that case, so verify by running with the profile and checking behavior.

## How do I set up a project config for a team repo?

Commit a `.codex/config.toml` at the repo root. Codex walks from the project root down to your working directory and loads each `.codex/config.toml` it finds. If several files define the same key, the one closest to your working directory wins. That lets a monorepo set a default at the root and a stricter one inside a package.

A conservative starting file:

```toml
# .codex/config.toml (committed)
sandbox_mode = "workspace-write"
approval_policy = "on-request"
```

Details that matter:

- **Trust gate.** Project layers load only when the project is trusted. In an untrusted project Codex skips project-scoped layers, including project-local config, hooks and rules. User and system config still load.
- **Relative paths.** Relative paths in a project file resolve against the `.codex/` folder that contains the `config.toml`, so committed paths work on every machine.
- **Project root.** A directory containing `.git` is the root by default. Change the markers with `project_root_markers`. An empty list treats the current working directory as the root.

### What a project file cannot set

A repo you cloned should not be able to redirect your traffic or turn on telemetry. So Codex ignores these keys in project files and prints a startup warning: `openai_base_url`, `chatgpt_base_url`, `apps_mcp_product_sku`, `model_provider`, `model_providers`, `notify`, `profile`, `profiles`, `experimental_realtime_ws_base_url` and `otel`.

Put these in `~/.codex/config.toml` instead, and choose profiles with `--profile`. This is a useful property when you open unfamiliar repos. It is still worth reading the `.codex/` folder, including its hooks and rules, before you trust a repo, because the trust decision is what turns those project layers on.

## How do I override one setting for a single run?

Use `-c` or `--config`. Prefer a dedicated flag such as `--model` when one exists.

```sh
codex --model gpt-6.1-sol
codex --config model='"gpt-6.1-sol"'
codex --config sandbox_workspace_write.network_access=true
codex --config 'shell_environment_policy.include_only=["PATH","HOME"]'
```

Notes from the docs:

- Values are parsed as TOML. If parsing fails, Codex treats the value as a string.
- Nested keys use dot notation, for example `mcp_servers.context7.enabled=false`.
- Quote anything with spaces or special characters so the shell does not split it.
- `sandbox_workspace_write.network_access` is a boolean. Setting it to `true` allows outbound network access inside the workspace-write sandbox, so it is safer to turn it on per run than in a committed file.
- `include_only` is a legacy array. It still works, but you cannot combine it with the newer `[shell_environment_policy.filters]` table in the same layer.

Because CLI overrides sit at the top, they are the right tool for a script that must force a setting no matter what the repo says.

## A layout that works

- `~/.codex/config.toml`: your model, effort and personal defaults, plus provider, notification and telemetry settings.
- `~/.codex/deep-review.config.toml` and similar: only the keys that differ.
- `.codex/config.toml` in the repo: sandbox and approval defaults the whole team shares.
- `--config` in scripts: one-off, visible overrides.

## Conclusion

Think of Codex configuration as a stack: CLI flags on top, then the repo, then your profile, then your user file. Keep shared defaults in the base file, put only differences in profile files, commit conservative project settings, and use `--config` for exceptions. If you upgraded recently, migrate any `[profiles.*]` tables first, since Codex 0.134.0 and later no longer read them.

## Questions people ask

### Where is the Codex config.toml file?

Your personal file is ~/.codex/config.toml. A repo can add a .codex/config.toml, which Codex loads only if you trust the project. On Unix there is also a system file at /etc/codex/config.toml.

### Does a project config override a Codex profile?

Yes. Project config files rank above a profile chosen with --profile, and CLI flags rank above both. The docs list one exception: if both a profile and the project set model_catalog_json, the profile value is used.

### Why does my Codex profile stop working after an update?

From Codex 0.134.0, --profile no longer reads [profiles.name] tables from config.toml, and the top-level profile = selector is no longer supported. Move the settings into ~/.codex/name.config.toml as top-level keys and remove the old table.

### How do I change one Codex setting for a single run?

Pass --config key=value (or -c). Values are parsed as TOML, nested keys use dots, and a dedicated flag like --model is preferred when it exists.

### Can a repo change my Codex model provider or telemetry?

No. Codex ignores keys such as model_provider, model_providers, notify and otel in project files and prints a startup warning. Set them in your own ~/.codex/config.toml.

## About Atlas: Per-role model and effort in Atlas

This article is about choosing model and effort per Codex run and per repo. Atlas is built on Claude Code, not Codex, so none of these files apply. In Atlas each AI engineer is its own Claude Code session with a written role, and its model and effort are tuned to that role. See the [Atlas home page](/atlas/). — https://bridge-terminal.com/atlas/

## Sources

- [Codex config basics](https://learn.chatgpt.com/docs/config-file/config-basic)
- [Codex advanced configuration: profiles, project config, overrides](https://learn.chatgpt.com/docs/config-file/config-advanced)
- [Codex configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference)

_Researched and drafted with Claude, then checked against the sources above. Atlas is an independent product, not affiliated with Anthropic or OpenAI._

## Related

- [Codex in CI: codex exec and the GitHub Action](https://bridge-terminal.com/atlas/blog/codex-exec-github-action-ci-review/)
- [Claude Code vs Codex for Teams: A Workflow Comparison](https://bridge-terminal.com/atlas/blog/claude-code-vs-codex-team-workflows/)
- [Codex CLI Setup: Install, Approval Modes and Sandboxing](https://bridge-terminal.com/atlas/blog/codex-cli-install-approval-modes-sandbox/)
