All use cases

Build an Internal Tool in a Week with Claude Code

Developer 1 week Intermediate

What you'll build

Internal tools are the highest-leverage software a small team can build. In a week you can replace three spreadsheets and a Slack channel with one app: SSO, a Postgres database, role-based access, audit logs, and a clean table-and-form UI. Built right, it pays for itself in time saved by the second week.

What you're building

You're building an internal app that replaces a specific workflow your team currently runs on spreadsheets, email threads, and copy-paste. Pick one concrete workflow: customer onboarding, refund approvals, vendor invoices, content moderation, lead routing. The narrower the workflow, the better the tool. A one-table-one-form internal tool that nails a daily workflow beats a five-feature dashboard that does nothing well. Don't try to build the company's operating system in a week. Build the thing that ends one specific spreadsheet.

By Friday you have an app behind your company SSO, a few roles like viewer and editor and admin, a table view of records with filter and search, a detail view with edit and history, and an audit log of every change. Teammates are logged in and using it. That last part is the real test. Internal tools that nobody opens are worse than spreadsheets, because the existence of an unused tool creates ambiguity about where the source of truth lives.

Pick a workflow that hurts every day, not one that hurts every quarter. Daily pain creates the demand pull that makes a tool stick. Quarterly pain creates a tool everyone forgets how to use by the time the next quarter rolls around. The hardest part of an internal tool isn't the build, it's the adoption, and daily pain handles adoption for you.

What you need before you start

Comfort with TypeScript and a working knowledge of SQL. An understanding of who'll use the tool and what they need to do every day, written down. Access to whatever data source the tool reads from, whether that's a production database, a Stripe account, or a Google Sheet. A place to deploy that your team can reach, either a Vercel project on a custom domain or a self-hosted box behind a VPN. A short conversation with the future users before any code is written, even thirty minutes, will save you a day of guessing.

  • Node 20 and pnpm
  • Claude Code installed and authenticated
  • Postgres via Supabase, Neon, or your existing database
  • Drizzle ORM or Prisma for typed queries
  • Clerk, WorkOS, or Supabase Auth for SSO
  • A short doc with the workflow and roles

Day one: spec and skeleton

Write a SPEC.md before you write code. List the user roles, the entities, the actions each role can take, and the screens. A page each: list view, detail view, create form, settings. Keep the screen count under five for v1. Ask Claude Code to scaffold a Next.js App Router project with Tailwind, shadcn/ui, Drizzle, and your auth provider. Confirm sign-in works end to end before adding anything else. Auth bugs in an internal tool block every other person on the team, so they're worth getting right before any feature lands on top.

Add a simple users table that mirrors your auth provider with a role column. Seed it with two test users, one admin and one viewer, and confirm role-based redirects work. This is the foundation everything else sits on. Get it right on day one. The audit log table goes in on day one too, even though you won't write to it until day two. Tables added later always end up backfilled with NULL, which makes them useless for the question you wanted to answer.

Day two and three: data and CRUD

Write the schema in Drizzle. Two or three tables for v1. Run a migration with drizzle-kit. Build the list view first with a server component that queries the table, a TanStack Table or a simple HTML table with sort and filter, and pagination. Don't load every row at once. Paginate from day one or the page locks up the moment the table has ten thousand rows. Cursor-based pagination scales further than offset pagination, and Claude will write either if you ask, so pick cursor.

Add the detail page next, then the create form, then the edit form. Use shadcn forms with react-hook-form and zod for validation. Every form should write through a server action that checks the user's role, validates the payload, writes to the database, and writes an audit log entry. The audit log is non-negotiable on internal tools. Day-two-you adds it. Day-fourteen-you thanks day-two-you when a teammate asks who changed the row, and day-ninety-you thanks both of them during the security review.

Day four: roles and permissions

Define three roles for v1: viewer, editor, admin. Viewer can read. Editor can create and update. Admin can delete and manage users. Build the permission helpers in lib/permissions.ts and call them from both the server actions and the UI components. The UI checks hide buttons. The server checks prevent abuse. Both are required. UI checks alone are security theatre, server checks alone are a confusing experience, and the combination is what production-quality internal tools look like.

Choices to make along the way

Clerk versus WorkOS versus Supabase Auth: Clerk is the fastest to set up for a typical SaaS-style internal tool and has great prebuilt components. WorkOS is the right choice if you need SAML SSO from day one because you're selling to enterprise. Supabase Auth is the cheapest and ties cleanly to a Supabase database. Pick by what your team's existing IDP is.

Drizzle versus Prisma: Drizzle is closer to raw SQL, gives you typed queries without a separate generation step, and is faster at runtime. Prisma has a friendlier query API but adds a build step and a heavier runtime. For an internal tool, Drizzle is the right default in 2026.

Day five: shipping

Deploy to Vercel on a subdomain like tools.yourcompany.com. Connect to the Postgres instance and confirm migrations run. Set every secret. Lock the subdomain behind a Vercel Access policy if you don't want it open to the web. Add a one-page README that tells teammates how to log in. Send a Slack message to the people who'll use it with screenshots and ask them to try it. Don't announce in a wide channel. Recruit two users by name first, then expand.

Sit with two of those teammates while they use the tool for ten minutes. Watch what confuses them. The things that confuse them are the things you fix on day six. The club at claudecodeclub.ai has a public internal-tools starter and a thread of teams running this exact playbook. Worth the nine dollars a month for the patterns alone, especially the role-design conventions.

How to test it

Write a TESTING.md with the five workflows that have to work: log in, list view with filters, create record, edit record, delete record as admin. Run the script in production before every deploy. Add Playwright tests for the two flows you broke at least once. Don't write a hundred tests up front. Write the ones you need after you need them.

How to extend it

Add CSV import and export, because internal tools without CSV are abandoned within a month. Add Slack notifications on state changes so the right people know without checking the tool. Add a saved-filter feature so users land on their own view. Add a small dashboard with two or three KPIs at the top. Add a job queue with Trigger.dev or Inngest if some actions take more than a few seconds. Each of those is a one-day add once the foundation is solid.

Common gotchas

Loading every row into the page on day three and forgetting to paginate. Skipping the audit log and regretting it on day fourteen. Sprinkling role checks across the codebase instead of centralizing them. Forgetting to add an index on the columns you filter and sort by, which makes the list view slow as the table grows. Forgetting to handle the deleted-by-someone-else case in the edit form, which throws a confusing error.

The biggest gotcha is treating an internal tool like a SaaS product. It's not. Visual polish matters less than getting the workflow right. A homely tool that nails the workflow gets opened daily. A beautiful tool with a clunky workflow gets opened once and abandoned.

Common questions

  • Which auth provider should I use?

    Clerk is fastest for typical setups and has great prebuilt components. WorkOS is right when you need SAML SSO from day one for enterprise sales. Supabase Auth is the cheapest and pairs cleanly with a Supabase database. Pick the one that matches your team's identity provider.

  • Drizzle or Prisma?

    Drizzle in 2026. It gives you typed queries without a code-generation step, runs faster, and stays closer to raw SQL when you need it. Prisma is friendlier at the query API level but heavier at runtime and at build time.

  • Where do permission checks belong?

    In a single permissions.ts file with named functions like canEditOrder(user, order). Both UI components and server actions call those helpers. UI checks hide buttons, server checks prevent abuse, and changing a rule means editing one file.

  • Do I need an audit log?

    Yes, from day two. Every write goes through a server action that records who did what and when. When a teammate asks who changed a row, you have an answer. Adding the log retroactively is much more work than building it in.

  • Should I write tests during the build?

    Keep a TESTING.md with the five critical workflows and run the manual script before every deploy. Add Playwright tests after you've broken a flow once in production. Don't front-load a hundred tests for an internal tool with a small user base.

  • Why pagination matters from day one?

    Without pagination, the list view loads every row in the table. The page is fast at a hundred rows and unusable at ten thousand. Adding pagination later means rewriting the list view, the filters, and the sort logic together.

More to build

Build it. Ship it. Get paid.

Step-by-step lessons for every one of these inside the club. Join Claude Code Club for $9/month.

Related: the library, guides, and comparisons.