Back to blog

Internal Tools Have a Half-Life. Here's Why.

Spencer Pauly
Spencer Pauly
5 min read
Internal Tools Have a Half-Life. Here's Why.

Every internal tool I've ever shipped has eventually broken, and I've watched the same thing happen at every company I've worked at. It's not bad engineering. It's a structural problem.

I want to lay out the four reasons internal tools rot, then explain why I think the answer is to stop building them as fixed apps and start building them as queryable interfaces. That second part is most of what QueryBear is.

Reason 1: They're built by engineers who leave

Someone gets a Slack ping that customer success can't see refunds. They spend a Friday afternoon spinning up a tiny Next.js page that lists refunds with a filter. It works. Six months later that engineer has changed teams or left the company. The page is still there. Then the schema changes and the page 500s.

Now the page is broken, and the only person who knew how it worked is gone. Nobody else's OKR includes "fix Sarah's refund tool." So it sits there, broken, until someone finally re-asks the engineering team to rebuild it from scratch.

I have personally written that page at three different companies. I will probably write it again.

Reason 2: Internal tools have no PM

Internal tools don't have a roadmap, a designer, or anyone who owns them past the day they're shipped. They're side projects of side projects.

This is fine for the first version. It's not fine over time. The product team doesn't know who uses them, what for, or what would make them better. The eng team doesn't know what's broken until someone files a ticket. The result is a graveyard of half-working apps that everyone has emotional opinions about and nobody is responsible for.

A team I worked with once had 23 distinct internal admin panels by the time I joined. Three of them did almost the same thing. Two were deprecated but still in production. One had a hardcoded list of admin emails from 2021.

Reason 3: They assume a static schema

This is the technical reason internal tools rot fastest.

You build a refund-management page, and it hardcodes column names and join paths. SELECT id, amount, reason FROM refunds JOIN orders ON refunds.order_id = orders.id WHERE… Then someone renames reason to refund_reason because legal asked. Or orders.id becomes orders.public_id because of a sharding migration. Or a new refund_status column gets added that the page doesn't know about, so refunds in a new state show up incorrectly.

Every schema change is a pull request someone has to open against every internal tool that touches that table. People don't open those PRs. They write a TODO and move on.

After enough schema migrations, your internal tools are quietly lying. The numbers look right. They aren't.

Reason 4: They solve last quarter's question

The dashboard you built six months ago answers questions you had six months ago. The business has moved on. Maybe revenue moved from per-seat to usage-based and the old MRR card is wrong. Maybe a new product line launched and the dashboard doesn't know about it. Maybe what mattered was "trial conversions" and now it's "expansion revenue."

Refreshing those dashboards every time priorities shift takes engineering time you don't have. So the dashboards drift, people stop trusting the numbers, and slowly everyone goes back to pinging the founder for the answer.

What I think actually fixes this

The realization I keep coming back to: most internal tools shouldn't be apps. They should be questions.

A refund admin panel is a fixed app. "Show me all refunds in the last 30 days, grouped by reason, with the original order amount" is a question. The first one breaks every quarter. The second one survives a column rename because you re-ask it and the answer comes out fresh.

That flips the whole maintenance model. Instead of an engineer-built app pinned to a snapshot of the schema, you have a thin layer that lets a human or an agent ask the database directly, get the current answer, and save the question if it's useful again. The database is the source of truth. The UI is whatever the question demanded that day.

This is the lane QueryBear is in. The "tools" we ship are saved questions with parameters, not static dashboards. When the schema changes, the AI re-resolves table and column names against the current schema and the question still works. When priorities shift, you write a new question instead of filing a Jira ticket against a project nobody owns.

It's not the answer to every internal tool. You still want a real app for things that need workflow logic, multi-step approvals, or write operations. But for the read-only "I just need to see this number" tools that make up 80% of any company's internal panel inventory, the right thing is a question, not an app.

The thing that breaks an internal tool is the fact that it's an app. Stop building apps and the thing stops breaking.

4 comments

  • engineering_today

    23 internal admin panels is a real number that I will be quoting at my next eng leadership meeting.

  • rachel.k

    I think the framing of 'questions, not apps' is mostly right but it ignores the workflow tools — refund issuance, account merges, the stuff that actually mutates data. Those are 30% of internal tools and they DO need to be apps.

  • dbarrr

    We had a Friday-afternoon admin panel break the day after a column rename and nobody noticed for three weeks because the page still rendered with stale data. Schema-drift bugs are silent and that's the worst part.

  • stillscaling

    Curious how you handle the 'I need a button to do thing X' use case in QueryBear. Saved queries are great for reads but reads aren't all of internal tooling.

Database Access

Give Your AI Agents
Database Access. Securely.

Connect any database. Control permissions. Audit every query. All running locally on your machine.