The Frustration That Started It All
Picture this: Youβre deep in a debugging session. Your terminal is split between your code editor, logs streaming in real-time, and a test runner. Youβre in the zone. Then you need to check a document in Firestore.
Alt-tab. Open browser. Navigate to Firebase Console. Wait for it to load. Click on your project. Wait again. Click Firestore. Expand the collection. Scroll. Find the document. Click it. Finally see the data.
By the time you get back to your terminal, youβve lost your train of thought. The context switch killed your flow.
If youβve worked with Firebase Firestore, you know exactly what Iβm talking about. The Firebase Console is fine for occasional use, but when youβre actively developing and need to check data constanβ¦
The Frustration That Started It All
Picture this: Youβre deep in a debugging session. Your terminal is split between your code editor, logs streaming in real-time, and a test runner. Youβre in the zone. Then you need to check a document in Firestore.
Alt-tab. Open browser. Navigate to Firebase Console. Wait for it to load. Click on your project. Wait again. Click Firestore. Expand the collection. Scroll. Find the document. Click it. Finally see the data.
By the time you get back to your terminal, youβve lost your train of thought. The context switch killed your flow.
If youβve worked with Firebase Firestore, you know exactly what Iβm talking about. The Firebase Console is fine for occasional use, but when youβre actively developing and need to check data constantly, it becomes a bottleneck.
I kept thinking: Why canβt I just browse Firestore from my terminal?
So I built it.
Introducing LazyFire
LazyFire is a terminal user interface (TUI) for browsing Firebase Firestore. Itβs heavily inspired by lazygit - the fantastic terminal UI for git that changed how many of us interact with version control.
The core philosophy is simple: stay in your terminal, stay in your flow.
LazyFire connects to your Firestore database using your existing Firebase CLI credentials. No separate authentication, no API keys to manage - if you can run firebase commands, you can run LazyFire.
The Interface
When you launch LazyFire, youβre greeted with a clean, multi-panel interface:
ββ Projects βββββ¬β Collections ββ¬β Tree ββββββββββββββ¬β Details βββββββββββββββ
β β β β β
β π₯ my-app β π users β βΌ π users β { β
β my-app-stg β π products β π user_001 β "name": "John Doe", β
β my-app-dev β π orders β π user_002 β "email": "john@...", β
β β π analytics β βΆ π products β "created": "2024..." β
β β β β } β
βββββββββββββββββ΄ββββββββββββββββ΄βββββββββββββββββββββ΄βββββββββββββββββββββββββ€
β Commands: GET users/user_001 β 234ms β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Five panels, each with a purpose:
- Projects - All your Firebase projects, pulled from your CLI config
- Collections - Root-level collections in the selected project
- Tree - Documents and subcollections in an expandable tree view
- Details - The selected documentβs data with syntax highlighting
- Commands - A log of API calls with timing information
You can navigate between panels with h and l (or arrow keys), and move within lists using j and k. If youβve used vim or lazygit, youβll feel right at home.
Feature Deep Dive
Let me walk you through the features that make LazyFire genuinely useful for day-to-day development.
Vim-Style Navigation
Everything is keyboard-driven. Hereβs the complete keybinding reference:
| Key | Action |
|---|---|
h β | Move to left panel |
l β | Move to right panel |
j β | Move down in list |
k β | Move up in list |
Tab | Jump to details panel |
Enter | Select item / Expand collection |
Space | Toggle expand/collapse |
v | Enter visual select mode |
F | Open query builder |
/ | Filter current panel |
c | Copy JSON to clipboard |
s | Save JSON to file |
e | Open in external editor |
r | Refresh current view |
? | Show help |
@ | Show command history |
Esc | Go back / Cancel |
q | Quit |
The beauty of these keybindings is muscle memory. After a few sessions, youβll be flying through your database without thinking about it.
Expandable Tree View with Subcollections
Firestoreβs nested structure is fully supported. When you select a collection, LazyFire loads its documents. Each document can be expanded to reveal its subcollections, which can themselves be expanded to show their documents, and so on.
βΌ π users
π user_001
βΌ π orders
π order_abc
π order_def
βΆ π items
βΆ π preferences
π user_002
βΆ π products
The arrow indicators (βΆ for collapsed, βΌ for expanded) make it easy to see the current state at a glance. Collection folders are cyan, document icons are green - subtle color coding that helps you parse the tree quickly.
Interactive Query Builder
This is one of my favorite features. Press F (Shift+F) on any collection or subcollection to open the query builder:
How it works:
- Navigate with
j/kbetween rows (WHERE, ORDER BY, LIMIT, buttons) - Navigate with
h/lbetween fields within a row - Press
Enterto edit a field - Press
ato add a new filter condition - Press
dto delete a filter - Tab through operators and value types using popup selectors
Supported operators:
- Comparison:
==,!=,<,<=,>,>= - Array operations:
in,not-in,array-contains,array-contains-any
Value types:
auto- LazyFire guesses the type (string, number, boolean)string- Force string interpretationinteger- Force integerdouble- Force floating pointboolean- Force booleannull- Null valuearray- Comma-separated values forin/not-inoperators
When you execute the query, results replace the tree view (or appear under the subcollection if you queried a nested collection). Itβs a massive time saver compared to writing queries in code or using the Firebase Console.
jq Query Support
The details panel shows your document as syntax-highlighted JSON. But what if you only care about a specific field? Or you want to transform the data before copying it?
Press / in the details panel and enter a jq expression:
| Filter | What it does |
|---|---|
.name | Extract just the name field |
.address.city | Nested field access |
.users[0] | First element of users array |
.users[].name | All names from users array |
| `.data \ | keys` |
| `.items \ | length` |
select(.status == "active") | Filter by condition |
The filtered result is displayed in the details panel. Hereβs the powerful part: when a jq filter is active, copy and save operations use the filtered result, not the full document.
This means you can:
- Open a complex document
- Filter to just the fields you need with
.data.users[].email - Press
cto copy only those email addresses to your clipboard
No more copying a massive JSON blob and manually extracting what you need.
Visual Select Mode
Sometimes you need to fetch multiple documents at once. Visual select mode makes this painless.
- Press
vin the tree panel to enter select mode - Move up/down with
j/kto extend your selection (works in both directions, like vim) - Selected documents are highlighted with a dim yellow
+marker - Press
Spaceto fetch all selected documents in parallel - Press
Enterto view the combined results - Press
Escto exit select mode
The parallel fetching is key here. Instead of fetching documents one by one (which would be slow due to network latency), LazyFire fires off all requests simultaneously. Even fetching 20 documents feels instant.
Smart Caching
Network calls are expensive. LazyFire implements a two-level caching system:
Document cache - Once you fetch a documentβs data, itβs cached. Youβll see a small yellow dot Β· next to cached documents in the tree.
1.
Collection cache - When you expand a collection, the list of documents is cached. Collapsing and re-expanding uses the cache instead of hitting the API again.
This makes navigation feel snappy. The first time you expand a collection, thereβs a brief loading spinner. After that, itβs instant.
The cache is session-based (cleared when you quit) and can be refreshed anytime with r.
Syntax Highlighting
Document JSON is displayed with full syntax highlighting using the chroma library:
- Keys are colored distinctly from values
- Strings, numbers, booleans, and nulls each have their own color
- Proper indentation for nested objects
- Large documents are scrollable
Itβs a small thing, but it makes a huge difference when youβre scanning through document data.
External Editor Integration
Press e in the details panel to open the current document in your external editor. LazyFire checks these environment variables in order:
$EDITOR$VISUAL- Falls back to
nvimif installed, otherwisevim
The document opens as a temporary JSON file. This is read-only for now (edits arenβt saved back to Firestore), but itβs useful when you need vimβs full power to search or analyze a complex document.
Customizable Themes
LazyFire comes with a clean default theme, but you can customize every color. Create a config file at ~/.lazyfire/config.yaml:
ui:
# Nerd Fonts version: "3", "2", or "" to disable icons
nerdFontsVersion: "3"
theme:
activeBorderColor:
- "#ed8796"
- bold
inactiveBorderColor:
- "#5f626b"
optionsTextColor:
- "#8aadf4"
selectedLineBgColor:
- "#494d64"
Color options:
- Named colors:
black,red,green,yellow,blue,magenta,cyan,white,default - Hex colors:
#ed8796,#ff79c6, etc. - 256-color palette: Numbers
0through255 - Attributes:
bold,underline,reverse
Example themes:
Catppuccin Macchiato:
ui:
theme:
activeBorderColor: ["#ed8796", "bold"]
inactiveBorderColor: ["#5f626b"]
optionsTextColor: ["#8aadf4"]
selectedLineBgColor: ["#494d64"]
Dracula:
ui:
theme:
activeBorderColor: ["#ff79c6", "bold"]
inactiveBorderColor: ["#6272a4"]
optionsTextColor: ["#8be9fd"]
selectedLineBgColor: ["#44475a"]
Tokyo Night:
ui:
theme:
activeBorderColor: ["#7aa2f7", "bold"]
inactiveBorderColor: ["#565f89"]
optionsTextColor: ["#7dcfff"]
selectedLineBgColor: ["#292e42"]
Mouse Support
While keyboard navigation is the primary interface, LazyFire also supports mouse input:
- Click on any panel to focus it
- Click on items to select them
- Click outside a popup to close it
This makes it accessible to team members who might not be familiar with vim-style navigation.
Nerd Font Icons
If you use a Nerd Font (and you should - theyβre great), LazyFire displays beautiful icons throughout the interface:
- π₯ Firebase flame for the welcome screen and projects
- π Folder icons for collections
- π Document icons for documents
- Various status indicators
If icons donβt display correctly, you can switch to Nerd Fonts v2 compatibility mode or disable icons entirely:
ui:
nerdFontsVersion: "2" # For older Nerd Fonts
# or
nerdFontsVersion: "" # Disable icons
Installation
Getting started takes less than a minute.
Homebrew (macOS/Linux)
brew tap marjoballabani/tap
brew install lazyfire
Go Install
If you have Go installed:
go install github.com/marjoballabani/lazyfire@latest
From Source
git clone https://github.com/marjoballabani/lazyfire.git
cd lazyfire
go build -o lazyfire .
./lazyfire
Download Binary
Pre-built binaries for macOS and Linux are available on the releases page.
Prerequisites
- Firebase CLI - Install with
npm install -g firebase-tools - Firebase Authentication - Run
firebase loginif you havenβt already - Terminal with true color support - Most modern terminals (iTerm2, Alacritty, Kitty, Windows Terminal) support this
- Nerd Font (optional) - For icons. Download here
Quick Start
Once installed, getting started is simple:
# Make sure you're logged in
firebase login
# Launch LazyFire
lazyfire
Youβll see a welcome screen with your Firebase projects. Use j/k to navigate, Enter to select a project, and start exploring.
Pro tip: If you work with multiple Firebase projects, LazyFire remembers them all. Switch between production, staging, and development environments without re-authenticating.
The Tech Behind It
For those curious about the implementation:
Language: Go - chosen for its excellent cross-platform support, single binary distribution, and strong concurrency primitives (goroutines make parallel document fetching trivial)
Terminal UI: gocui - Jesse Duffieldβs fork of the gocui library, which powers lazygit. Itβs battle-tested and handles all the complexity of terminal rendering.
jq Implementation: gojq - A pure Go implementation of jq. No external dependencies, works on all platforms.
Syntax Highlighting: chroma - Fast, accurate syntax highlighting with theme support.
Firebase API: Direct REST API calls using the access token from Firebase CLI. No Firebase Admin SDK means fewer dependencies and a smaller binary.
The entire application is around 5,000 lines of Go code. Itβs not a massive project, but every feature is intentional and polished.
Why I Built This
Iβll be honest: I built this for myself.
I spend most of my working day in the terminal. Neovim for editing code, lazygit for version control, various CLIs for deployment and infrastructure. My terminal is my IDE, and Iβve optimized it over years to minimize friction.
But Firestore was always the exception. Every time I needed to check a document or verify that a write succeeded, I had to leave my terminal and open a browser. It broke my concentration every single time.
One day, after the hundredth alt-tab to the Firebase Console, I thought: "lazygit exists for git... why doesnβt something like this exist for Firestore?"
I couldnβt find anything that fit the bill, so I built it.
The first version was rough - just enough to browse collections and view documents. But over time, I kept adding features that would save me time:
- "I keep running the same queries" β Query builder
- "I just want to see one field" β jq support
- "Fetching documents one by one is slow" β Visual select mode + parallel fetching
- "I hate waiting for data to load again" β Caching
Each feature came from real frustration during real development work. Thatβs why LazyFire feels cohesive - itβs not a collection of features someone thought might be useful, itβs a collection of solutions to problems I actually had.
Whatβs Next
LazyFire is actively maintained and I have a roadmap of features Iβm considering:
Near-term:
- Document editing (create, update, delete) - currently read-only
- Batch operations on selected documents
- Export to CSV format
Medium-term:
- Firestore emulator support for local development
- Realtime listeners for live document updates
- Saved queries that persist across sessions
Long-term:
- Firebase Auth user browsing
- Cloud Functions log viewing
- Multiple database support (for projects with multiple Firestore instances)
If any of these would be particularly useful for your workflow, let me know in the comments or open an issue on GitHub. User feedback directly influences what I prioritize.
Try It Out
The project is open source under the MIT license:
github.com/marjoballabani/lazyfire
If you work with Firestore and spend any amount of time in the terminal, give it a try. The installation takes 30 seconds, and you might find it changes how you interact with your database.
Stars on GitHub are always appreciated - they help others discover the project. And if you run into any issues or have feature requests, please open an issue. I read every single one.
About Me
Iβm Marjo Ballabani, a software developer who believes that good developer tools should get out of your way. I build things that make my workflow faster, and sometimes those things are useful to others too.
You can find me on GitHub where I occasionally open source projects like this one.
What terminal tools have changed your workflow? Iβd love to hear about your favorite TUIs and CLI tools in the comments below!