npm.io
2.0.0 • Published 1 week agoCLI

firestore-indexes-diff

Licence
MIT
Version
2.0.0
Deps
4
Size
37 kB
Vulns
0
Weekly
0
Stars
3

Firestore Indexes Diff

npm license typescript vitest

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 for the file format.

Quick Start

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
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.

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
# Which indexes does production not have yet?
pnpm dlx firestore-indexes-diff --source dev-indexes.json --target prod-indexes.json
Staging Environment Sync
# 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.

- 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
# 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

# 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 ./scripts/verify-package.sh

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

License

MIT Omar Dulaimi

Keywords