Building an internal tool instead of buying Retool
When the build-your-own internal tool is the right call — the cost comparison most teams skip, and the surprisingly small Next.js + Postgres scaffold that replaces Retool for many use cases.
For a single-user "admin dashboard" that touches your existing database and supports your existing ops team, building it yourself in Next.js is faster and cheaper than buying Retool. The point at which Retool genuinely beats build-your-own is when you have a non-engineering team building five or more internal tools — at that scale Retool's drag-and-drop and per-tool maintenance amortize beautifully. For most early-stage SaaS, that scale never arrives, and the Retool license becomes annual rent on a tool you could have shipped in a week. The decision isn't ideological — it's about how many internal tools you'll actually build.
We've shipped internal tools both ways. This is the framework.
The numbers
Retool's published pricing (2026): ~$10/user/month for the cheapest plan that's actually production-usable. For a team of 5 ops + 2 engineers = $840/year. Plus a couple of hours of engineer time per month maintaining the Retool apps.
Build-your-own: 2-5 days of senior engineering to ship the first version. Negligible ongoing cost. Lives in the same repo as your main app, shares the same auth, shares the same database connection.
The crossover is roughly:
- 1-3 internal tools needed → build your own
- 4-10 internal tools needed → roughly even, depends on team skills
- 10+ internal tools needed across multiple teams → Retool
Most early-stage SaaS lands firmly in the first bucket.
What an internal tool actually needs
The 80/20 of internal-tool features:
- A list / search of records — "show me all users, filter by signup date"
- A detail view — "show me everything about this user"
- A handful of actions — "grant this user a free month," "refund this charge," "delete this account"
- An audit trail — who did what when
- Auth gating — only employees can access this
Five things. None of them require a low-code platform.
The scaffold that replaces most Retool use
We build internal tools as a section of the main Next.js app under /admin. The full setup:
src/app/admin/
├── layout.tsx # auth gate + nav
├── page.tsx # dashboard / quick stats
├── users/
│ ├── page.tsx # list + search
│ ├── [id]/page.tsx # detail view
│ └── actions.ts # server actions for ops
├── orgs/
│ └── ...
└── audit/
└── page.tsx # who did whatAuth gate:
// src/app/admin/layout.tsx
import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
const session = await auth();
if (!session?.user.isStaff) redirect("/");
return <div className="admin">{children}</div>;
}That's the entire access control. isStaff is a flag on the users table; only your team can flip it. If you want to be paranoid, gate it behind an additional IP allowlist or a hardware-key requirement.
A list view in ~50 lines
// src/app/admin/users/page.tsx
import Link from "next/link";
import { db } from "@/lib/db";
export default async function AdminUsersPage({
searchParams,
}: {
searchParams: Promise<{ q?: string }>;
}) {
const { q } = await searchParams;
const users = await db.users.findMany({
where: q ? { email: { contains: q, mode: "insensitive" } } : undefined,
orderBy: { createdAt: "desc" },
take: 100,
});
return (
<div className="p-6">
<form>
<input name="q" defaultValue={q} placeholder="Search by email" />
</form>
<table className="mt-4 w-full">
<thead><tr><th>Email</th><th>Plan</th><th>Joined</th></tr></thead>
<tbody>
{users.map((u) => (
<tr key={u.id}>
<td><Link href={`/admin/users/${u.id}`}>{u.email}</Link></td>
<td>{u.plan}</td>
<td>{u.createdAt.toISOString().slice(0, 10)}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}A search-as-you-type version takes one more useDebounce hook. A pagination version takes 10 more lines. A CSV export takes an API route. None of this is hard.
Actions with audit
The pattern for an action — say, "grant this user a free month":
// src/app/admin/users/actions.ts
"use server";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
export async function grantFreeMonth(userId: string) {
const session = await auth();
if (!session?.user.isStaff) throw new Error("unauthorized");
await db.$transaction(async (tx) => {
await tx.subscriptions.update({
where: { userId },
data: { trialEnd: addDays(new Date(), 30) },
});
await tx.auditEvents.create({
data: {
actorId: session.user.id,
kind: "grant_free_month",
targetType: "user",
targetId: userId,
details: { days: 30 },
},
});
});
revalidatePath(`/admin/users/${userId}`);
}Every action follows the same pattern: auth check, transactional change, audit log row. After 10 actions you have a clear pattern and the next one takes 10 minutes.
What Retool genuinely beats build-your-own at
Honest list:
- Non-engineers building tools. A finance person who wants to build a dashboard without filing a ticket. Retool wins.
- Many small one-off queries. "Show me this thing for this customer." Spinning up a Retool app for each is faster than coding routes for each.
- Built-in connectors. Retool talks to Stripe, Salesforce, Snowflake, Segment, your warehouse, your task queue, all in their UI. Wiring those up in Next.js takes more code.
- A unified UI across many tools. All tools have a similar look without you designing one.
- Permissions across many tools. Retool's RBAC is more flexible than what you'd ship hand-rolled.
If those bullets describe your team, Retool is worth it. Don't be ideological.
The cost no one factors in: developer drag
A subtle reason build-your-own often wins for engineering-led teams: the cost of context-switching out of your codebase to a low-code tool.
When the admin dashboard lives in /admin of your main app, an engineer fixing a customer issue can:
- Read the bug report
- Open the admin tool to look at the customer's data
- Spot the bug
- Open the source code (same project, same IDE)
- Fix it
- Ship
When the admin dashboard lives in Retool, step 4 requires opening a different tab and a different mental model. Multiply by every ops-driven bug and you've paid a real cost.
What about Forest Admin / RetoolXY / Appsmith?
Same trade-offs as Retool. Forest Admin is the closest to "free admin panel for your DB" but the customization story gets bumpy when your model is non-trivial. Appsmith is open-source self-host (no license fee) but you're now operating a separate service.
The pattern: any tool that adds a "second source of truth" or "second runtime" for your app is incurring a cost. Sometimes the cost is worth it.
When the build-your-own approach hurts
I'll be fair to Retool. The cases where the home-grown version goes wrong:
- One engineer leaves and no one knows the admin code. Internal tools rot fastest because no one is monitoring them. Fix: include them in tests, even shallow ones.
- The schema changes and the admin breaks silently. Foreign key renames, column drops. Strong CI helps.
- A non-engineer asks for a new admin feature and waits two weeks. Fix: pair an ops person with an engineer for a day, ship a batch of small features at once.
These are real but manageable. Retool's marketing argues they prevent these by making non-engineers self-serve. In practice we've seen Retool apps rot just as fast — orphaned dashboards no one maintains, queries that broke after a schema change three months ago and no one noticed.
What we ship as the default admin scaffold
For most customer engagements:
/admin/*routes in the same Next.js app, gated byisStaff- Users / orgs / subscriptions list + detail views
- Common actions: impersonate user, refund charge, grant plan, force re-verify email
- Audit log table + viewer
- A few "ops queries" surfaced — "users who churned in the last 7 days," "subscriptions that failed payment"
That's a one-week build at week 4 of a SaaS MVP — see how to build a SaaS MVP in 6 weeks. It saves quarters of "can you run this SQL for me" Slack messages.
Need an admin panel that doesn't bleed your roadmap?
We build internal tools and ops dashboards in the same Next.js stack as your main app — fast to ship, cheap to maintain.
FAQ
What if my ops team has zero engineers?
Then Retool is genuinely the right call. The whole point of low-code is to lower the bar. Don't fight it.
Can I start with build-your-own and switch to Retool later?
Yes — and you might. The investment in /admin isn't wasted; you can keep the most-used routes and migrate the long-tail to Retool. We've seen this exact pattern.
How do I do "give an ops person edit access to one specific column"?
In Retool: their RBAC. In build-your-own: code the form to only show that column. Trade-off is real, but for the typical case (5-10 ops actions) coding it is faster than wiring Retool's RBAC.
What about Supabase Studio / Hasura Console?
Useful for direct database editing for engineers. Not a replacement for an admin tool aimed at ops. Different layer.
How do I show charts and dashboards?
Postgres queries + a chart library (recharts or tremor). About a day of work for a comprehensive metrics dashboard. Significantly less than the Retool-equivalent.
Should I use Forest Admin instead?
Forest is a fine middle ground if you want a generated admin from your schema with light customization. We default to hand-rolled because we usually want significant customization and the generated UI breaks once you stray.
What about no-code tools like Bubble for internal tools?
Bubble is aimed at building products, not admin. Wrong fit.
Can I expose this admin to customers as a self-serve thing?
Yes — and that's the natural next step. Many "internal admin" features become "customer self-serve" features over time. Building them in your main codebase makes that transition seamless.