When developing firestore based apps (especially for the server) I often find it a bit tricky to inspect "intermediate" query results, or just to play around with data, test queries and so on. I found a few admin interfaces but they generally appear to be for the realtime database and almost universally have no commits for 1-2 years.

Ideally I'd just be able to type commands into a terminal and try queries out. It turns out using a node repl this is very easy to do. I found some instructions for building your own REPL, and adapted them for firestore admin.

Here is what my REPL looks like:

//repl.ts

import * as repl from 'repl'
import initFirestoreAdmin from './src/initAdmin' 
      // used by my functions to init admin with credentials etc

const admin = initFirestoreAdmin()
const firestore = admin.firestore()

const replServer = repl.start({
  prompt: 'fb > '
})

replServer.context.firestore = firestore
replServer.context.admin = admin

// I can also save typing by doing things like:
replServer.context.userId = 'my_firestore_user_id'

// or by adding functions
replServer.context.withUser = query => 
  query.where('userId', '==', replServer.context.userId)

I'm coding in typescript, so I also yarn add --dev ts-node so I don't have to bother with compiling the ts file. I can then add a script to my package.json:

"scripts": {
  ...,
  "repl": "./node_modules/.bin/ts-node repl.ts
}

I can start the repl from the root directory with yarn repl. A prompt appears, and I can start typing in firestore queries:

// get the pages collection
fb > firestore.collection('pages').get().then(result => console.log(result))

// get a user's pages
fb > withUser(firestore.collection('pages')).get().then(result => console.log(result.size))

Using this approach you could also pull in any of your application code (for instance GraphQL resolvers), and have a ready built console application version for your app.

A note on async/await

By default, the node repl doesn't support async/await. It's available under a feature flag in node 10+, but doesn't appear to be available in ts-node yet. You can provide async functionality by installing async-repl and using it as follows:

// inside repl.ts
import * as stubber from 'async-repl/stubber'

//
//set up your repl as above...
//

stubber(replServer)

Now in your repl you can do the following:

fb > const docs = await firestore.collection('documents').get()