Self-hosted accounting app crafted for freelancers, indie-hackers and small businesses. Let AI scan your receipts, analyze your expenses, convert currencies, and get your taxes in order.
Built with Next.js 16, React 19, Prisma 7, and PostgreSQL. Made with β€οΈ in India.
- Upload receipts or invoices as photos or PDFs for automatic recognition
- Extract key information like dates, items, and vendors
- Works with any language and any photo quality
- Automatically organize everything into a structured database
- Bulk upload and analyze multiple files at once
- Automatically detects foreign currencies and converts them to yours
- Knows historical exchange rates for the transaction date
- Supports 170+ world currencies and popular cryptocurrencies (BTC, ETH, LTC, etc.)
- Manual entry always available as a fallback
- Fully customizable categories, projects, and custom fields
- Add, edit, and manage your transactions
- Filter by any column, category, or date range
- Customize which columns to show in the table
- Import transactions from CSV
- Advanced invoice generator to create invoices in any language
- Edit any field, even labels and titles
- Export invoices to PDF or as transactions
- Save invoices as templates to reuse later
- Native support for included and excluded taxes (VAT, GST, etc.)
- Expand and improve your instance with custom LLM prompts
- Create custom fields/categories and tell AI how to parse them
- Extract any additional information you need
- Automatically categorize by project or category
- Ask AI to assess risk level or any other criteria
- Bring your own keys: OpenAI, Google Gemini, Mistral
- 100% self-hosted for complete privacy
- Export transactions to CSV for tax prep
- Full-text search across documents and invoices
- Download your full data archive at any time β we never lock your data
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI | React 19, Tailwind CSS 4, Radix UI |
| Database | PostgreSQL with Prisma 7 ORM |
| Auth | Better Auth (email OTP) |
| AI/LLM | LangChain + OpenAI / Google Gemini / Mistral |
| Emails | Resend |
| Payments | Stripe (optional) |
| Deployment | Docker, Docker Compose |
- Node.js β₯ 26 (see
.nvmrc) - PostgreSQL database (local or hosted)
- One AI provider API key (Gemini recommended β free)
npm installCreate a .env file in the project root:
# Core
NODE_ENV=development
PORT=7331
BASE_URL=http://localhost:7331
# Database (required)
DATABASE_URL=postgresql://USER:PASSWORD@localhost:5432/taxhacker
# Auth
BETTER_AUTH_SECRET=a-very-long-random-secret-at-least-16-chars
# AI (pick at least one β Gemini is free via Google AI Studio)
GOOGLE_API_KEY=your-gemini-api-key
GOOGLE_MODEL_NAME=gemini-2.5-flash
# Emails (optional, for OTP login in cloud mode)
RESEND_API_KEY=re_your-resend-key
RESEND_FROM_EMAIL=TaxHacker <onboarding@resend.dev>npx prisma migrate deploynpm run devOpen http://localhost:7331 in your browser.
The project includes a multi-stage Dockerfile and several docker-compose files.
Use docker-compose.build.yml to build locally:
# Set required env first
export POSTGRES_PASSWORD=your-db-password
export BETTER_AUTH_SECRET=your-long-secret
# Build and start
docker compose -f docker-compose.build.yml up -d --buildMigrations run automatically on startup. The app will be available at http://localhost:7331.
docker compose up -d| Service | Description |
|---|---|
app |
The Next.js web application (port 7331) |
cron |
Background jobs (email sync, log rotation) |
postgres |
PostgreSQL 17 database |
Data persistence: Uploads are stored in
./dataand the database in./pgdataβ both are mounted as volumes.
TaxHacker can run in two modes, controlled by the SELF_HOSTED_MODE env variable:
| Mode | SELF_HOSTED_MODE |
Login for users? | Best for |
|---|---|---|---|
| Self-hosted | true |
β No login (single shared user) | Personal / private / local use |
| Cloud | false |
β Email-OTP signup & login | Sharing with multiple users |
- Everyone who opens the app uses one shared workspace β no signup, no payment
- No email provider or Stripe needed
- Ideal for a personal instance or a trusted team on a private network
- Each user signs up with their email + OTP code
- Requires a Resend API key to send OTP emails
- Optional Stripe for paid subscriptions
- Ideal for a public SaaS you share with others
For a free, no-credit-card deployment you can share with others, use:
| Service | Purpose | Free tier |
|---|---|---|
| Render.com | Web hosting (Docker) | 750 hrs/month, spins down when idle |
| Neon / Supabase | PostgreSQL database | 512 MB storage |
| Resend | OTP emails (cloud mode only) | 100 emails/day |
| Google AI Studio | Gemini API key (AI) | Generous free tier |
- Push this repo to GitHub.
- Sign up at render.com (free, no card).
- Create a New β Web Service, connect your GitHub repo.
- Set Environment to
Docker. - Add the environment variables from the section below.
- Click Create Web Service β Render builds & deploys automatically.
- Done! You get a free
https://your-app.onrender.comURL with HTTPS.
| Variable | Value |
|---|---|
NODE_ENV |
production |
PORT |
7331 |
BASE_URL |
https://your-app.onrender.com (your actual URL) |
SELF_HOSTED_MODE |
true (free, no login) or false (multi-user) |
DATABASE_URL |
Your Neon/Supabase Postgres connection string |
BETTER_AUTH_SECRET |
A random string β₯ 16 chars |
GOOGLE_API_KEY |
Your free Gemini key |
GOOGLE_MODEL_NAME |
gemini-2.5-flash |
RESEND_API_KEY |
Only if cloud mode (false) |
RESEND_FROM_EMAIL |
Only if cloud mode (false) |
Important:
BASE_URLmust match your public URL exactly (includinghttps://). It's used for OTP links and redirects.
Generate a strong auth secret:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"- Go to Google AI Studio
- Sign in β Create API key
- Paste it as
GOOGLE_API_KEY
| Variable | Required | Default | Description |
|---|---|---|---|
BASE_URL |
β | http://localhost:7331 |
Public URL of the app |
PORT |
7331 |
Port the app listens on | |
SELF_HOSTED_MODE |
true |
true = no login, false = cloud login |
|
DATABASE_URL |
β | β | PostgreSQL connection string |
BETTER_AUTH_SECRET |
β | β | Auth secret (β₯ 16 chars) |
DISABLE_SIGNUP |
false |
Set true to block new signups |
|
GOOGLE_API_KEY |
β | Gemini API key | |
GOOGLE_MODEL_NAME |
gemini-2.5-flash |
Gemini model | |
OPENAI_API_KEY |
β | OpenAI API key | |
OPENAI_MODEL_NAME |
gpt-4o-mini |
OpenAI model | |
MISTRAL_API_KEY |
β | Mistral API key | |
MISTRAL_MODEL_NAME |
mistral-medium-latest |
Mistral model | |
RESEND_API_KEY |
cloud only | β | Resend key for OTP emails |
RESEND_FROM_EMAIL |
cloud only | β | Verified sender email |
RESEND_AUDIENCE_ID |
β | Resend audience for newsletters | |
STRIPE_SECRET_KEY |
optional | β | Stripe payments |
STRIPE_WEBHOOK_SECRET |
optional | β | Stripe webhooks |
UPLOAD_PATH |
/data/uploads |
Where uploads are stored |
A copy-paste template with descriptions is available in .env.example.production.
components/ # React UI components (dashboard, forms, transactions, etc.)
app/ # Next.js App Router pages & API routes
lib/ # Core logic (auth, db, config, email, files, stats)
models/ # Database models / data access layer
prisma/ # Prisma schema & migrations
ai/ # AI/LLM integration (providers, prompts, schema)
forms/ # Form validation schemas (Zod)
hooks/ # Custom React hooks
public/ # Static assets (images, fonts, landing media)
docs/ # Additional documentation
types/ # TypeScript type definitions
# Run the test suite (Vitest)
npm test
# Run tests in watch mode
npm run test:watch
# Lint the codebase
npm run lintDEPLOYMENT.mdβ Free, no-credit-card deployment guidedocs/self-hosted-public-access.mdβ Exposing self-hosted instances publiclydocs/migrate-0.3-0.5.mdβ Migrating data from older versions
- Check Resend dashboard β Logs for delivery status.
- Emails from
onboarding@resend.devmay land in Spam. Verify a domain in Resend for better delivery.
- Ensure
DATABASE_URLis correct and includes?sslmode=requirefor hosted databases like Neon.
- You have
SELF_HOSTED_MODE=trueorDISABLE_SIGNUP=true. For open signups set both tofalse.
- The app allows up to 256 MB uploads by default. Increase
bodySizeLimitinnext.config.tsif needed.
- This is fixed in the current
Dockerfile(uses the explicit binary path). Pull the latest image.
This is an open-source project. Contributions, bug reports, and feature requests are welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Made with β€οΈ in India by @Daksh
- Support / Contact: djain00009@gmail.com
- Source Code: github.com/Daksh200/Invoice_IQ
No license β all rights reserved. Use at your own risk.
- Built using Next.js, Prisma, Better Auth, LangChain, and Tailwind CSS