Firetool

Home / Docs / Import

Docs

Import CSV or JSON into Firestore

Load a CSV or JSON file into a Firestore collection, with the right type for every column, your own document IDs, nested fields, and a choice between updating and replacing documents that already exist. You need Firetool Pro.

Start an import

  1. Open the collection you want to import into. It can be a subcollection, such as users/alice/orders.
  2. Choose Import in the toolbar above the results. Or right-click the collection in the sidebar and choose Import… (JSON or CSV).
  3. Pick a file. Firetool takes .csv and .json files only. Excel files need to be saved as CSV first.

A CSV file opens the Import CSV dialog and a JSON file opens Import JSON. If the JSON file is a Firetool backup, Firetool opens Restore a backup instead, so subcollections and exact values come back as they were (see Backup and restore).

Imports need Firetool Pro. You can't import into a collection group tab (one with Group ticked), because a group has no single place to add documents: open one of its collections by its full path instead.

Import a CSV file

The first row of the file must be the header, with one column name per field. Firetool reads UTF-8 files, with or without a BOM, and quoted values that contain commas or line breaks.

  1. Check the summary at the top: the file name, the number of rows and columns, and the project and collection it goes into.
  2. Choose the Document ID column. Firetool picks __id if the file has it (as in Firetool's own exports), or a column named id, uid, docid or document_id. Choose None: create new documents with automatic IDs to add every row as a new document.
  3. Choose what happens to Existing documents: Update only the columns in this file (the default) or Replace the whole document. See Existing documents.
  4. Leave Columns with dots are nested fields ticked to turn a column named address.city into the field city inside the map address, the same way Firetool's CSV export names them. Untick it to keep the dot in the field name.
  5. Check the type of every column in the table. Each row shows the column, its type and an example value from the file.
  6. Choose Import N rows.

Empty cells are skipped: the field isn't written for that row. A __path column (from a collection group export) is ignored.

Before anything is written, Firetool converts every row. If a value doesn't fit its column's type, or a row has no ID or an ID with a slash, it shows the rows to fix and nothing is imported.

Column types

The type list offers string, number, boolean, timestamp, reference, geopoint, json and null. Firetool fills it in for you: from the type the field already has in the documents loaded in the tab, otherwise by looking at the first 500 values. It guesses number only for values with fewer than 10 digits and no leading zero, so mobile numbers and codes such as 0987 stay string. Shorter codes, such as a 6-digit PIN code, can still be guessed as numbers: set them to string.

TypeWhat the cell can hold
stringAny text, stored exactly as it is.
number42 is stored as an integer, 12.5 as a decimal. Integers too large for JavaScript keep their exact digits (64-bit). NaN, Infinity and -Infinity also work.
booleantrue, yes or 1; false, no or 0. Upper or lower case.
timestampA date and time, such as 2026-03-01T09:30:00Z or 2026-03-01 09:30. A full time with a zone (as Firetool exports it) is kept exactly, microseconds included. Without a zone, your computer's time zone is used.
referenceA document path in the same database, such as users/u17. A leading / is dropped.
geopoint17.385,78.4867 (latitude, longitude), or JSON such as {"lat": 17.385, "lng": 78.4867}.
jsonA JSON array or object, stored as a Firestore array or map: ["a","b"], {"qty": 1}.
nullEvery cell in the column, empty or not, is stored as null.

Import a JSON file

The file can be either of these:

  • A list of objects, one per document: [{"__id": "c001", "name": "Asha"}, …]. This is what Firetool's JSON export makes.
  • An object of ID to document: {"c001": {"name": "Asha"}, "c002": {…}}. Each key becomes the document ID.

In a list, "__id" sets the document ID; items without it get a new automatic ID. An ID can't be empty or contain a slash. "__path" is ignored. Values keep their types with the same notation as the export: {"$timestamp": "…"}, {"$ref": "users/u17"}, {"$geo": {"lat": …, "lng": …}}, {"$bytes": "…"} (base64), {"$int": "…"} for 64-bit integers and {"$double": 10} for a whole number that must stay a decimal. Plain numbers follow JSON: 10 is an integer, 10.5 a decimal.

The Import JSON dialog says how many documents it found and how many have an "__id". Choose Import N to start.

Existing documents

This choice matters only for rows or items that have a document ID. Without an ID, each one is always a new document.

  • Update only the columns in this file (CSV) or Update only the fields in the file (JSON): writes only the fields in the file and keeps every other field of an existing document. For nested fields it goes into the map: address.city changes the city and keeps the rest of address. If the document doesn't exist yet, it's created.
  • Replace the whole document: the document becomes exactly what's in the file. Fields that aren't in the file are removed.

The defaults differ: CSV starts on Update only the columns in this file, JSON on Replace the whole document. The JSON dialog shows the choice only when at least one item has an "__id".

Batches, stopping and resuming

  • Firetool writes 500 documents per request. Each batch of 500 is all or nothing: either every document in it is saved, or none are.
  • The dialog shows Importing 500 of 2,000… as it goes, and the job appears in Tasks (Ctrl+Shift+J).
  • Choose Cancel while it runs to stop after the current batch. If a batch fails, for example because the network dropped, the import stops too.
  • The button then reads Resume, and the dialog says how many documents are saved. Resume imports the rest. Automatic IDs are chosen once, so resuming never creates the same row twice.
  • When it finishes, the tab runs its query again so you see the new documents.

Production, policy and copies

  • If the project or database is marked production, an import of more than one document asks you to type the project ID once, in Confirm a production change, before the first batch.
  • If the policy asks for a reason for every change, you're asked for one, and it's saved in the audit log.
  • A project or database marked read-only, or a Viewer role, can't import: the Import button is turned off.
  • Every batch is written to the audit log. By default, an import of several documents doesn't keep restorable copies of the documents it overwrites. To keep them, set Keep restorable copies of to Everything that changes (more reads) in Tools → Policy and roles. For a safety net before a large import, back up the collection first.

Example: CSV with phone numbers kept as text

Import this file into customers:

id,name,phone,pin,joined,active,address.city,manager
c001,Asha Rao,9876543210,500081,2026-03-01T09:30:00Z,true,Hyderabad,users/u17
c002,Ravi Kumar,09123456780,560034,2026-03-04T11:00:00Z,false,Bengaluru,
  1. Open customers, choose Import and pick the file.
  2. Document ID column is already id.
  3. Check the types. In an empty collection Firetool guesses them from the file: phone is string (10 digits, and one starts with 0). Change pin from number to string. joined is timestamp and active is boolean. Change manager from string to reference.
  4. Leave Columns with dots are nested fields ticked, and choose Import 2 rows.

Document c001 then looks like this in the JSON editor:

{
  "name": "Asha Rao",
  "phone": "9876543210",
  "pin": "500081",
  "joined": { "$timestamp": "2026-03-01T09:30:00Z" },
  "active": true,
  "address": { "city": "Hyderabad" },
  "manager": { "$ref": "users/u17" }
}

c002 has active: false and no manager field, because its cell was empty.

Example: JSON

[
  {
    "__id": "c003",
    "name": "Meera Iyer",
    "phone": "9988776655",
    "joined": { "$timestamp": "2026-03-10T08:00:00Z" },
    "office": { "$geo": { "lat": 13.0827, "lng": 80.2707 } },
    "tags": ["gold", "chennai"],
    "address": { "city": "Chennai", "pin": "600001" }
  },
  { "name": "Walk-in customer", "phone": "9000000001" }
]

Import it into customers. The first item becomes c003 with a timestamp, a geopoint, an array and a map. The second gets an automatic ID. Choose Update only the fields in the file if c003 already exists and you want to keep its other fields.

Questions

Can I import an Excel file?

Not directly. In Excel, choose Save As and pick CSV UTF-8, then import the CSV. Set mobile numbers, PIN codes and account numbers to string in the import dialog.

Can I undo an import?

Not with one click by default, because imports don't keep copies of the documents they overwrite. Back up the collection first, or set Keep restorable copies of to Everything that changes (more reads) so the audit log can restore them.

Does an import cost reads?

An import writes one document per row or item. An import of several documents doesn't read the existing ones first, unless your policy keeps copies of everything that changes.