---
url: https://findutils.com/guides/toml-diff
title: "Review Cargo.toml and pyproject.toml Changes Without Formatting Noise"
description: "See what a Cargo.toml or pyproject.toml change really does: compare the parsed values by path, so reordered keys, comments and table style drop out. Runs in your browser."
category: developer
content_type: guide
guide_type: subtopic
cluster: config
locale: en
read_time: 7
status: published
author: "olgunozoktas"
published_at: 2026-09-25T12:00:00Z
excerpt: "A formatter reorders a manifest, someone turns a dependency table into dotted keys, and the pull request shows forty changed lines. Usually one version number moved. Comparing the parsed TOML instead of the text shows which one."
tag_ids: ["config", "toml", "diff", "developer-tools"]
tags: ["Config", "TOML", "Diff", "Developer Tools"]
primary_keyword: "cargo.toml diff"
secondary_keywords: ["pyproject.toml diff", "semantic toml diff", "compare toml ignoring key order", "review dependency changes toml", "toml diff online"]
tool_tag: "toml-diff"
related_tool: "toml-diff"
related_tools: ["toml-diff", "yaml-toml-converter", "json-toml-converter", "json-diff", "env-diff"]
og_image: "/images/content/guides/toml-diff-cover-20260925.webp"
image_alt: "Two matching wooden organiser trays of pebbles, wooden beads and glass marbles; in the right tray one compartment holds amber marbles and one bead is a darker wood."
updated_at: "2026-09-25T12:00:00Z"
---

To review a Cargo.toml or pyproject.toml change without formatting noise, compare the two files by parsed value instead of by line. FindUtils [TOML Diff](/developers/toml-diff/) parses both versions and reports each real difference at its TOML path, such as `dependencies.serde` or `project.version`, so reordered keys, comments, whitespace and table style do not show up. The files are compared in your browser and are not uploaded.

This guide explains why line diffs of TOML are noisy, how to read the path report, how arrays behave, and which changes the comparison cannot hide or explain.

## Why a Line Diff of TOML Is Noisy

TOML lets you write the same data several ways. The [TOML 1.0 specification](https://toml.io/en/v1.0.0) says dotted keys "create and define a table for each key part before the last one", so `fruit.apple.color = "red"` builds the same tables as `[fruit]` and `[fruit.apple]` headers. Inline tables in curly braces are a third spelling of the same thing.

These three blocks hold identical data:

```toml
[dependencies.tokio]
version = "1"
features = ["full"]
```

```toml
[dependencies]
tokio.version = "1"
tokio.features = ["full"]
```

```toml
[dependencies]
tokio = { version = "1", features = ["full"] }
```

A line diff reports every line of that change. A value comparison reports nothing, because nothing changed. The same applies to keys moved to a different position in a table, blank lines, alignment spaces and comments.

## How to Compare Two Versions

### Step 1: Get the before and after

Copy the old file from the base branch and the new one from the pull request, or save both from your editor. Any TOML document works: `Cargo.toml`, `pyproject.toml`, `rustfmt.toml`, `ruff.toml`, `netlify.toml` and so on.

### Step 2: Paste or drop them

Open [TOML Diff](/developers/toml-diff/) and put the old version in the Before (A) pane and the new one in After (B). Rename the panes if you want the report to say `main` and `feature-branch`.

### Step 3: Compare

Press Compare. The summary counts added, removed and changed paths. Turn on Show unchanged paths to list every leaf that matched as well.

### Step 4: Keep the report

Copy it, or download `toml-diff-report.txt` or `toml-diff-report.json` for the review thread.

## How to Read the Paths

Each line of the report is one path in the parsed document:

| Report line | Meaning |
|---|---|
| `~ package.version: "0.1.0" → "0.2.0"` | The value at that path changed |
| `- dependencies.serde = "1.0"` | The key exists only in the old file |
| `+ dependencies.anyhow = "1"` | The key exists only in the new file |
| `+ tool = {"ruff":{"line-length":100}}` | A whole new table; it appears once, with its contents |
| `~ a[1]: 2 → 3` | The second element of the array `a` changed |
| `~ "my key": 1 → 2` | A key that is not a bare key is shown in quotes |

A table that is new in B is reported as one added path holding the whole table, not as one line per key inside it. The same goes for a table that was removed.

## Arrays Compare by Position

TOML arrays are ordered, so TOML Diff compares them element by element: index 0 with index 0, index 1 with index 1. That keeps the report exact, but it has a consequence when an item is inserted at the front or in the middle.

Changing `features = ["derive"]` to `features = ["std", "derive"]` reports `features[0]` changed from `"derive"` to `"std"` and `features[1]` added as `"derive"`. Nothing was lost, but every element after the insertion point looks changed. When a report shows a run of changed indexes, read the old and new arrays side by side before concluding that items were replaced.

This matters most in files built from arrays of tables. `Cargo.lock` is TOML, and its `[[package]]` entries are one array: a package added near the top shifts the index of every package after it.

## What Still Counts as a Change

The comparison ignores formatting, not meaning. These do show up:

- **A type change.** `version = 1` and `version = "1"` are an integer and a string, so the path is reported as changed.
- **A table replacing a value.** When `serde = "1.0"` becomes `serde = { version = "1.0", features = ["derive"] }`, the path `dependencies.serde` is reported as changed from a string to a table.
- **A date.** Dates and times are compared by their TOML text, so `2024-01-01` and `2024-01-02` differ.

One distinction is not kept: an integer and a float with the same value, such as `1` and `1.0`, compare as equal, although the TOML specification treats integers and floats as separate types.

## When a File Does Not Parse

If either side is not valid TOML, the comparison stops and names the side that failed, with the line and column. A common cause is a key defined twice, which the specification forbids outright ("Defining a key multiple times is invalid"), so a bad merge that leaves two `version` lines in one table fails here instead of passing silently. Fix the file, then compare again.

## Where the Formats Are Defined

The layout of these files is set by their own specifications, which say what each table means:

- `Cargo.toml` is described in the [Cargo manifest reference](https://doc.rust-lang.org/cargo/reference/manifest.html).
- `pyproject.toml` is described in the [pyproject.toml specification](https://packaging.python.org/en/latest/specifications/pyproject-toml/) from the Python Packaging Authority.

TOML Diff checks structure and values, not whether a key is allowed by Cargo or by a Python build backend. It does not look up package versions either, so a bumped version is reported without any statement about what the new release contains.

## Common Mistakes

**Expecting a merged file.** TOML Diff only reports differences. To move a config between formats, use [YAML TOML Converter](/developers/yaml-toml-converter/) or [JSON TOML Converter](/developers/json-toml-converter/).

**Reading an array shift as many edits.** An insertion early in an array makes later indexes look changed. Check the arrays before reverting anything.

**Comparing a partial copy.** If you paste only the `[dependencies]` block from one side and the whole file from the other, everything outside that block is reported as added or removed.

## Tools Used in This Guide

| Tool | Use |
|---|---|
| [TOML Diff](/developers/toml-diff/) | Compare two TOML files by parsed value and path |
| [YAML TOML Converter](/developers/yaml-toml-converter/) | Convert between YAML and TOML |
| [JSON TOML Converter](/developers/json-toml-converter/) | Convert between JSON and TOML |
| [JSON Diff](/developers/json-diff/) | The same kind of path comparison for JSON files |
| [Env Diff](/developers/env-diff/) | Compare two .env files by key |

## FAQ

### How do I see only the real changes in a Cargo.toml pull request?

Paste the old and new Cargo.toml into TOML Diff. Only paths whose values were added, removed or changed are listed, so key reordering, comments, spacing and switches between `[table]`, dotted keys and inline tables disappear from the report.

### Does switching a dependency to an inline table count as a change?

No, when the keys and values stay the same. `[dependencies.tokio]` with `version = "1"` and `tokio = { version = "1" }` parse to the same table, so no difference is reported.

### Why does one inserted array item show several changes?

Arrays are compared by position. Inserting an item shifts every later element to the next index, so each shifted index is reported as changed and the last one as added.

### Can I compare Cargo.lock files?

Yes, Cargo.lock is TOML. Its `[[package]]` entries form one array, so an added or removed package shifts the indexes of the entries after it and the report grows accordingly. For lock files, read the added and removed entries rather than counting changed indexes.

## Next Steps

Paste your before and after manifests into [TOML Diff](/developers/toml-diff/). For configuration kept in dotenv files, compare them with [Env Diff](/developers/env-diff/).
