# firestore-indexes-diff

> Displays differences between two Firestore index config files

Latest version **2.0.0** (published 2026-07-28) · MIT license · 0 weekly downloads

## Install

```sh
npm install firestore-indexes-diff
pnpm add firestore-indexes-diff
yarn add firestore-indexes-diff
bun add firestore-indexes-diff
```

Provides the command `diff-indexes`.

## Health

**Score 55/100 (C)** — status: active.

Positive: esm support; no vulnerabilities; has provenance.

Warnings: low downloads; no types.

## Facts

| | |
|---|---|
| Version | 2.0.0 |
| Published | 2026-07-28 |
| First published | 2023-02-04 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | ESM |
| Node | >=22.12.0 |
| Dependencies | 4 |
| Unpacked size | 36.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 3 |
| Author | Omar Dulaimi |
| Maintainers | omar-dulaimi |
| Keywords | firestore, firestore-indexes-diff |

## Links

- npm: https://www.npmjs.com/package/firestore-indexes-diff
- Repository: https://github.com/omar-dulaimi/firestore-indexes-diff
- Homepage: https://github.com/omar-dulaimi/firestore-indexes-diff#readme
- Issues: https://github.com/omar-dulaimi/firestore-indexes-diff/issues
- npm.io page: https://npm.io/package/firestore-indexes-diff

## Dependencies (4)

- [ora](https://npm.io/package/ora.md) ^9.4.1
- [chalk](https://npm.io/package/chalk.md) ^6.0.0
- [figlet](https://npm.io/package/figlet.md) ^1.11.4
- [commander](https://npm.io/package/commander.md) ^15.0.0

## Recent versions

- 2.0.0 (latest) — 2026-07-28
- 1.0.1 — 2025-10-16
- 0.0.2 — 2023-02-18
- 0.0.1 — 2023-02-04

## README

# 🔍 Firestore Indexes Diff

<div align="center">

[![npm](https://img.shields.io/badge/npm-firestore--indexes--diff-c53635?logo=npm)](https://www.npmjs.com/package/firestore-indexes-diff) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![typescript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![vitest](https://img.shields.io/badge/tested%20with-vitest-6E9F18?logo=vitest)](https://vitest.dev/)

</div>

A CLI tool that reports which Firestore indexes and field overrides exist in one
index configuration file but are missing from another, so you can catch gaps
before deploying across environments.

## ✨ Features

- 🚀 Compare Firestore index configurations between environments
- 📊 Report indexes and field overrides that the target file lacks
- 🧠 Normalises the implicit trailing `__name__` field, so a server export
  compares correctly against a hand-written file
- 💡 Colourful CLI output when attached to a terminal, quiet and parseable when
  piped
- 📁 Export differences to JSON files for further analysis

## 📋 Requirements

- **Node.js 22.12 or newer.** Earlier versions cannot parse the JSON import
  attribute this CLI uses. `npm install` will warn you if your Node is too old.

You also need two Firestore index configuration files. See the
[Cloud Firestore Index Definition Reference](https://firebase.google.com/docs/reference/firestore/indexes)
for the file format.

## 🚀 Quick Start

### Using pnpm dlx (Recommended)

```bash
pnpm dlx firestore-indexes-diff --source dev.json --target prod.json
# npx firestore-indexes-diff --source dev.json --target prod.json
# yarn dlx firestore-indexes-diff --source dev.json --target prod.json
```

### Global Installation

```bash
pnpm add -g firestore-indexes-diff
# npm install -g firestore-indexes-diff
# yarn global add firestore-indexes-diff

diff-indexes --source dev.json --target prod.json
```

### Try it against the bundled samples

The repository ships two sample files. `sample/dev_indexes.json` declares a
`users` index and a `posts` index; `sample/prod_indexes.json` declares only the
`users` one.

```bash
git clone https://github.com/omar-dulaimi/firestore-indexes-diff.git
cd firestore-indexes-diff
pnpm install
pnpm run build

node lib/bin/index.js --source sample/dev_indexes.json --target sample/prod_indexes.json
cat diff-indexes.json
```

That writes a `diff-indexes.json` holding the one `posts` index that production
is missing. No `diff-field-overrides.json` appears, because neither sample file
declares any field overrides.

## ⚙️ Options

| Option      | Alias | Type   | Required | Description              |
| ----------- | ----- | ------ | -------- | ------------------------ |
| `--source`  | `-s`  | string | ✅       | Source indexes file path |
| `--target`  | `-t`  | string | ✅       | Target indexes file path |
| `--version` | `-v`  |        |          | Show version number      |
| `--help`    | `-h`  |        |          | Show help                |

Paths may be relative to the current directory or absolute.

## 📤 Output

The comparison is one-directional: it answers "what is in the source file but
not in the target file". Results are written to the current directory.

| File                        | Contents                                             |
| --------------------------- | ---------------------------------------------------- |
| `diff-indexes.json`         | Indexes present in the source, missing in target     |
| `diff-field-overrides.json` | Field overrides present in source, missing in target |

Each file is written only when there is something to report, and **an existing
file is deleted when there is nothing to report**. That keeps the presence of a
file a truthful signal, so a CI check can test for it without being tripped up
by output left over from an earlier run.

The exit code is `0` for a successful comparison, whether or not differences were
found, and `1` if a file could not be read, is not valid JSON, or is not a
Firestore index file.

## 🔬 How indexes are compared

Two indexes are considered the same when their `collectionGroup`, `queryScope`,
`apiScope`, `density`, `multikey`, `unique` and `fields` all agree, following the
equality rules that firebase-tools uses.

Some details worth knowing:

- **The implicit `__name__` field is normalised.** Firestore appends a trailing
  `__name__` field to every composite index, so a file produced by
  `firebase firestore:indexes` always carries it while a hand-written
  `firestore.indexes.json` never does. Both sides are normalised before
  comparing, otherwise every index in a server export would be reported as
  missing.
- **Field order within an index matters**, because it is significant to
  Firestore. `[a, b]` and `[b, a]` are different indexes.
- **Key order inside the JSON does not matter.** A field written as
  `{"fieldPath": "a", "order": "ASCENDING"}` matches one written as
  `{"order": "ASCENDING", "fieldPath": "a"}`.
- **An omitted optional value equals its default.** An absent `apiScope` matches
  an explicit `ANY_API`, and an absent `ttl` on a field override matches an
  explicit `ttl: false`, which is what a server export writes.
- **Field override index lists are order-insensitive**, matching firebase-tools:
  what matters is the set of enabled modes, not the order they appear in.

## 🔄 Workflow Examples

### Development to Production Comparison

```bash
# Which indexes does production not have yet?
pnpm dlx firestore-indexes-diff --source dev-indexes.json --target prod-indexes.json
```

### Staging Environment Sync

```bash
# Ensure staging has all the indexes from development
pnpm dlx firestore-indexes-diff --source dev-indexes.json --target staging-indexes.json
```

### CI/CD Integration

`firebase firestore:indexes` needs the Firebase CLI and credentials for the
project, so this snippet assumes both are already configured.

```yaml
- name: Check Firestore Index Completeness
  run: |
    # Export the indexes currently deployed to production.
    firebase firestore:indexes --project "$PROJECT_ID" > prod-indexes.json

    # Compare the committed index file against what is deployed.
    npx firestore-indexes-diff --source firestore.indexes.json --target prod-indexes.json

    # Fail if anything in the committed file is not deployed yet.
    if [ -f "diff-indexes.json" ]; then
      echo "Missing indexes detected!"
      cat diff-indexes.json
      exit 1
    fi
```

### Multi-Environment Validation

```bash
# Check multiple environments in sequence
for env in dev staging prod; do
  echo "Checking $env environment..."
  npx firestore-indexes-diff \
    --source master-indexes.json \
    --target "$env-indexes.json"
done
```

## 🛠️ Development

```bash
# Clone the repository
git clone https://github.com/omar-dulaimi/firestore-indexes-diff.git
cd firestore-indexes-diff

# Install dependencies
pnpm install

# Compile TypeScript to lib/
pnpm run build

# Compile in watch mode
pnpm run dev

# Lint and run the test suite
pnpm run lint
pnpm run test:run
```

### Verifying the published artifact

The test suite includes end-to-end tests that spawn the compiled binary, because
unit tests that import the source modules directly cannot see a failure in the
CLI entry point. On top of that, this script packs the tarball, installs it into
an empty directory and runs the documented command against it:

```bash
bash ./scripts/verify-package.sh
```

CI runs it on Node 22 and 24 for every push.

## 📝 License

MIT © [Omar Dulaimi](https://github.com/omar-dulaimi)

---
_Source: https://npm.io/package/firestore-indexes-diff · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
