How We Built an AI Invoice Generator with Next.js and Tailwind
04/05/2026
How We Built an AI Invoice Generator with Next.js and Tailwind

A deep dive into the Eonebill tech stack — Next.js 15, Tailwind CSS, shadcn/ui, Prisma, and AI-powered invoice generation.

Building a SaaS product in the AI space means constantly choosing between shipping fast and building maintainable systems. When we started Eonebill — an AI-powered invoice generator for freelancers and small businesses — we had to make hard decisions about our tech stack. This is the story of what we chose and why.

The Stack at a Glance

Here's our core technology stack:

  • Framework: Next.js 15 (App Router)
  • Styling: Tailwind CSS + shadcn/ui
  • Database: PostgreSQL with Drizzle ORM
  • Auth: Better Auth (Google, GitHub, email)
  • Payments: Stripe (subscriptions + one-time)
  • AI: OpenAI GPT-4o + Replicate (image generation)
  • i18n: next-intl (English + Chinese)

Why Next.js 15?

When we started in early 2025, Next.js 14 was dominant and Next.js 15 was in beta. We made a bet on the newer version — and it paid off.

Server Actions changed how we think about form submissions. Invoice creation, client management, payment recording — all handled by server actions with zero API boilerplate. The type safety from next-safe-action means our Zod schemas double as both runtime validators and TypeScript types.

'use server'

import { z } from 'zod'
import { safeAction } from '@/lib/safe-action'

const createInvoiceSchema = z.object({
  clientId: z.string().uuid(),
  items: z.array(z.object({
    description: z.string().min(1),
    quantity: z.number().positive(),
    rate: z.number().nonnegative(),
  })),
  dueDate: z.string().datetime(),
  notes: z.string().optional(),
})

export const createInvoice = safeAction(createInvoiceSchema, async (parsed) => {
  const invoice = await db.insert(invoices).values({
    ...parsed.data,
    userId: await getCurrentUserId(),
  }).returning()
  return invoice[0]
})

The App Router's nested layouts made our multi-tenant structure natural. Each workspace has its own layout, and since everything is server-rendered by default, our invoices load fast even on slower connections.

Tailwind CSS + shadcn/ui: The Right Balance

We evaluated a few UI approaches. Component libraries like MUI felt heavy and "enterprise-y." CSS-in-JS added runtime overhead we didn't want. Tailwind + shadcn/ui hit the sweet spot.

shadcn/ui isn't a component library you install — it's copy-paste code you own. When we needed a data table for our invoice list, we pulled the Radix-based table component and customized it to match our design system. Zero npm dependency lock-in.

Tailwind's @apply directives let us create semantic utility classes for our design tokens:

@layer components {
  .invoice-card {
    @apply bg-white border border-gray-200 rounded-xl shadow-sm
           hover:shadow-md hover:border-blue-200 transition-all duration-200;
  }

  .invoice-status-paid {
    @apply bg-green-50 text-green-700 border border-green-200;
  }

  .invoice-status-overdue {
    @apply bg-red-50 text-red-700 border border-red-200;
  }
}

The result? A design system that feels cohesive but isn't strangling us with abstraction.

Prisma → Drizzle ORM

We switched from Prisma to Drizzle after hitting migration speed issues in development. Drizzle's schema-as-code approach felt more like writing SQL, which our team appreciated:

// drizzle.config.ts
import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
})

Migrations are fast, the ORM is lean, and the generated SQL is actually readable. For a product where query performance directly affects invoice generation speed, this matters.

AI in Invoice Generation

Here's where it gets interesting. The "AI" in AI Invoice Generator isn't a buzzword — it's integrated at multiple layers:

1. Invoice Auto-population Users describe their project in natural language. GPT-4o parses the description and suggests line items, quantities, rates, and even payment terms based on industry norms.

2. Smart Follow-ups When an invoice goes overdue, our AI analyzes the client's payment history and the invoice context to suggest a personalized follow-up message. Not a generic "please pay" email — something contextual.

3. Description Enhancement Freelancers often write vague line item descriptions. Our AI can take "design work" and expand it to "UI/UX design services — 3 logo concepts with 2 revision rounds" based on the broader context of the engagement.

The i18n Challenge

Supporting English and Chinese wasn't just about translation strings. Invoice standards differ between the US and China — tax IDs, currency formatting, legal disclaimers, even the concept of a "receipt" vs. an "invoice" varies. We solved this with next-intl's message files and locale-specific invoice templates:

messages/
  en.json
  zh.json

Each locale has its own invoice template configuration. The same underlying data renders differently based on the user's locale.

What We'd Do Differently

If we started today, we'd probably consider:

  • tRPC for end-to-end type safety between frontend and backend
  • Vercel AI SDK from day one instead of rolling our own AI integration layer
  • Drizzle Analytics earlier for understanding user behavior in invoice creation flows

But overall, the stack has held up well. We shipped Eonebill to production in under 3 months, and the codebase is still something our team enjoys working in.


The AI invoice generator space is crowded, but most competitors are either template editors with a thin AI wrapper, or enterprise tools that charge $99/month minimum. We built Eonebill for the freelancer who wants AI superpowers without the enterprise complexity.

Try Eonebill free at https://www.eonebill.ai — AI-powered invoice generation for freelancers and small businesses, starting at $0.

Originally published at Eonebill — AI-powered invoice generator for freelancers and small businesses.

Ready to automate your invoicing? Try Eonebill free — no credit card required.

Start Free →

Ready to automate your invoicing? Try Eonebill free — no credit card required.

Start Free →

Newsletter

Join the community

Subscribe to our newsletter for the latest news and updates