Firetool

Home / Docs / The firetool command

Docs

Query and change Firestore from the terminal

The firetool command is Firetool without its window. It uses the same accounts, roles, project rules and audit log as the app, so you can read data in a script, export it on a schedule or check it in CI.

Reading works in the Free edition and needs no licence. Changing data (set, update, delete, export, import and changing users) needs Pro on that computer, as in the app.

Set it up

The command comes with Firetool from the download page; there's nothing else to install. In Firetool, choose Help → Use Firetool from the terminal…: it shows where the command is on your computer and the one command that puts it on your PATH, with a button to copy it.

SystemWhere it isTo use it anywhere
Windowsbin\firetool.cmd in Firetool's program folder (usually %LOCALAPPDATA%\Programs\Firetool)Run the PowerShell line Help → Use Firetool from the terminal… gives you once, then open a new terminal.
macOSInside the app: Firetool.app/Contents/Resources/bin/firetoolsudo ln -sf "/Applications/Firetool.app/Contents/Resources/bin/firetool" /usr/local/bin/firetool
Linuxfiretool (the .deb and the .tar.gz install it)Nothing to do.

Check it works:

firetool version
firetool help

The command uses the accounts you added in Firetool, and it works while Firetool is open.

Read data

# The accounts added in Firetool, and the projects of one
firetool accounts
firetool projects

# A project's databases, its top-level collections, and those under a document
firetool databases shop-production
firetool collections shop-production
firetool collections shop-production users/alice

# One document
firetool get shop-production users/alice

# Documents that match, sorted, at most 20
firetool query shop-production orders --where "status == paid" --where "total >= 100" --order "total desc" --limit 20

# Every collection called orders (a collection group)
firetool query shop-production orders --group --where "status == refunded"

# How many documents match (one read per 1,000 counted)
firetool count shop-production orders --where "status == paid"

# Authentication users
firetool users list shop-production --limit 50
firetool users get shop-production ada@example.com

--where takes "<field> <op> <value>", where op is one of == != < <= > >= in not-in array-contains array-contains-any starts-with. Numbers, true / false and null are read as such; put text that looks like a number in quotes ("pin == '007'"). Lists are a,b,c or ["a","b"]. query reads 50 documents unless you give --limit (up to 10,000).

Output for scripts

The command prints tables for people. Add --json for scripts; query also takes --format jsonl (one document per line) or --format csv.

firetool query shop-production orders --where "status == paid" --json
firetool query shop-production orders --format csv > orders.csv

JSON keeps exact values in Firetool's form, such as {"$timestamp": "2026-01-01T00:00:00Z"}, so nothing loses its type.

Change data (Pro)

# Write a whole document, or change only some fields of one that exists
firetool set shop-staging settings/app --data '{"maintenance": false, "version": 3}'
firetool update shop-staging users/alice --data '{"plan": "pro"}'
firetool update shop-staging users/alice --file alice.json

# Delete one document
firetool delete shop-staging users/test-user --yes

# Export what matches to a file (.json, .jsonl or .csv), and import it again
firetool export shop-production orders --where "status == paid" --out paid-orders.jsonl
firetool import shop-staging orders --file paid-orders.jsonl --skip-existing

# Users
firetool users disable shop-production uid1 uid2
firetool users enable shop-production uid1
firetool users delete shop-staging uid3 --yes

--data and --file use Firetool's JSON form, so types are kept ({"at": {"$timestamp": "2026-01-01T00:00:00Z"}}). import reads what export writes; --skip-existing keeps documents that are already there. Add --dry-run to set, update, delete, import or a user change to see what would be written, without writing anything.

Every change goes through the same checks as the window: your role, read-only and production projects, protected collections, and the audit log, where it's marked as coming from the terminal.

Confirmations

Where the window would ask you something, the terminal can't, so the command stops with exit code 4 and tells you which option answers it. Run it again with that option:

  • --confirm <project-id>: the project is marked production and the change needs its project ID typed.
  • --reason "…": your policy asks for a reason. It goes in the audit log.
  • --yes: deleting, or reading more than 10,000 documents.
firetool delete shop-production users/old-test --yes --confirm shop-production --reason "Removing a test account"

Options

OptionWhat it does
--account <id or name>Which account to use, when several can open the project.
--db <database>A database other than (default).
--jsonMachine-readable output.
--format table|json|jsonl|csvFor query, how to print; for export, the file's format (otherwise from the file name).
--where, --orderFilters and sorting; both can be repeated. --order "total desc".
--limit <n>At most n documents (query: 50 by default) or users (100 by default).
--groupEvery collection with that name (query, count, export).
--data, --fileThe fields for set and update; the documents for import.
--out <path>The file export writes.
--skip-existingImport: keep documents that already exist.
--confirm, --reason, --yesAnswers to the window's questions (above).
--dry-runShow what would be written, and write nothing.
--key-file <path>A service account key for this run only (below).

Exit codes

CodeMeaning
0Done.
1Failed (the message says why).
2Wrong usage: a missing argument or an option it doesn't know.
3Needs Firetool Pro.
4Needs a confirmation: run it again with the option it names.
5Refused by the rules: your role, a read-only project or a protected collection.

CI and servers

On a build server there are no Firetool accounts, so give the command a service account key for the run:

  • --key-file key.json, or the file's path in FIRETOOL_KEY_FILE, or
  • the key's JSON itself in FIRETOOL_KEY, which suits a CI secret.

The key is used for that run only: it's used by default, never saved and never printed. On Linux without a display, the command runs headless. Reading needs no licence; changing data needs Pro on that machine.

Firetool has to be installed on the runner from the Linux .deb or .tar.gz you download from firetool.in. For example, keep the installer where your runner can reach it, then:

name: Check orders
on:
  schedule:
    - cron: "0 6 * * *"
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      # The Firetool installer, downloaded from firetool.in and kept in the repository
      - name: Install Firetool
        run: sudo apt-get install -y ./ci/Firetool-linux-x64.deb
      - name: Count paid orders
        env:
          FIRETOOL_KEY: ${{ secrets.FIRETOOL_KEY }}
        run: |
          firetool count shop-staging orders --where "status == paid"
          firetool query shop-staging orders --where "total < 0" --json > bad-orders.json

Give the service account only the roles it needs, such as Cloud Datastore Viewer for a job that only reads. The project rules you set in Firetool on that machine still apply.

Questions

Does the command need Firetool to be closed?

No. It works while Firetool is open, with the same accounts.

Do changes from the terminal go in the audit log?

Yes. Every change goes through the same checkpoint as the window and is recorded in the audit log, marked as coming from the terminal.

Is the key I give in CI kept anywhere?

No. A key from --key-file, FIRETOOL_KEY_FILE or FIRETOOL_KEY is used for that run only. It isn't saved with Firetool's accounts and isn't printed.