Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DentalERP - Free Open Source Dental Clinic Management Software for India

A comprehensive, AI-powered dental hospital management system built with Next.js 16, designed for dental clinics and multi-branch hospital chains in India. Includes GST-compliant billing, Razorpay/PhonePe/Paytm payments, patient portal, tele-dentistry, 16 AI skills, and more — completely free and open source.

Looking for dental practice management software in India? DentalERP is a free alternative to expensive proprietary dental software. Self-host it on your own server with full control over your patient data.

Features

Core Modules

  • Patient Management — Records, medical history, dental charting, document uploads
  • Appointment Scheduling — Calendar view, slot management, reminders, no-show prediction
  • Treatment Plans — Treatment tracking, procedure catalog, AI-assisted treatment advice
  • Billing & Invoicing — GST-compliant invoicing, payment tracking, payment plans (EMI)
  • Prescriptions — Digital prescriptions, medication database, print/PDF export
  • Inventory Management — Stock tracking, low-stock alerts, AI-powered demand forecasting
  • Lab Integration — Lab order management, status tracking, work coordination
  • Staff Management — Roles & permissions, attendance, doctor schedules

Advanced Features

  • AI Skills (16 built-in) — Treatment advisor, smart scheduler, billing agent, patient intake, inventory forecaster, cashflow forecaster, patient segmentation, claim analyzer, consent generator, dynamic pricing, and more
  • Patient Portal — Online booking, medical records access, digital intake forms
  • Insurance & Claims — Insurance verification, claim submission, auto-adjudication
  • CRM & Loyalty — Patient segmentation, loyalty points, referral tracking
  • Communications — SMS/Email/WhatsApp messaging, campaign management, marketing automation
  • Tele-Dentistry — Video consultations via Jitsi Meet integration
  • Sterilization Tracking — Instrument management, sterilization logs, compliance reporting
  • Dental Imaging — Interactive SVG dental arch viewer with condition mapping
  • IoT Device Integration — Medical device data logging and monitoring
  • Payment Gateways — Razorpay, PhonePe, Paytm integration (encrypted credentials)
  • Reports & Analytics — Revenue, appointments, treatment stats, exportable to Excel
  • Audit Logging — Full audit trail for compliance
  • Multi-branch Support — Hospital-scoped data isolation via NextAuth

Tech Stack

Layer Technology
Framework Next.js 16 (App Router)
Language TypeScript 5
Database MySQL 8 via Prisma 5 ORM
Auth NextAuth v5 (beta) with credentials provider
UI Tailwind CSS 3 + Radix UI + shadcn/ui
Charts Recharts
Forms React Hook Form + Zod validation
AI OpenRouter (multi-model gateway)
Email Nodemailer (SMTP)
Testing Vitest + Playwright + Testing Library
CI/CD GitHub Actions

Prerequisites

  • Node.js 20 or later
  • npm 10 or later
  • Docker with Compose v2 — recommended, but optional

Getting Started

git clone https://github.com/abinauv/dental-erp.git
cd dental-erp
npm install
cp .env.example .env

# Start MySQL, Redis, MinIO and Mailpit
docker compose -f docker-compose.dev.yml up -d

# Set DATABASE_URL in .env to match the container:
#   DATABASE_URL="mysql://root:dental@localhost:3306/dental_erp"

npx prisma migrate deploy   # create the schema
npx prisma db seed          # sample data (optional)
npm run dev

Open http://localhost:3000.

You still need to fill in NEXTAUTH_SECRET, ENCRYPTION_KEY and CRON_SECRET in .env — the app will not start without them. Each one has a node -e "..." command beside it in .env.example that prints a valid value.

The app runs on your machine, not in Docker. Compose brings up the backing services only. Bind-mounting node_modules into a container is slow enough on Windows and macOS to spoil the edit-reload loop, and native hot reload is better. docker-compose.dev.yml is a convenience for contributors and is never suitable for production — every credential in it is weak and public.

What Compose gives you

Service Port What it is for
MySQL 3306 The application database
Redis 6379 Reserved for caching and queues; nothing uses it yet
MinIO 9000, 9001 S3-compatible storage; reserved for Phase 3. Console on 9001
Mailpit 1025, 8025 Captures every outbound email. Read them at http://localhost:8025

Mailpit is the useful one right away. Point the SMTP_* variables at it (the values are commented into .env.example) and you can exercise password resets, invitations and reminders with no credentials and no risk of emailing a real person.

createbuckets runs once, creates the MinIO bucket and exits. Seeing it as Exited (0) in docker compose ps is success, not a failure.

Useful commands:

docker compose -f docker-compose.dev.yml logs -f      # tail the services
docker compose -f docker-compose.dev.yml down         # stop, keep the data
docker compose -f docker-compose.dev.yml down -v      # stop and wipe the data

Port 3306 already in use? You have MySQL installed locally. Either stop it, or change the host port in docker-compose.dev.yml to '3307:3306' and update DATABASE_URL to match.

If you were running this stack before August 2026, its compose project was renamed from dental-erp to dental-erp-dev, so that a production stack on the same machine cannot end up sharing volumes with it. Your old containers and volumes are still there under the previous name; clean them up once with:

docker compose -p dental-erp -f docker-compose.dev.yml down -v

Alternative setup: without Docker

Install MySQL 8 yourself

Docker is not a requirement. With MySQL 8.0+ installed locally:

# Verify MySQL is accessible
mysql -u root -p -e "SELECT 1"

# Create the database
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS dental_erp"

Then set DATABASE_URL in .env to your own credentials and continue from npx prisma migrate deploy above.

About the database setup

prisma migrate deploy is the recommended path — it is repeatable and safe to re-run when you upgrade. npx prisma db push also works and is handy while developing, but it applies the schema without recording it in prisma/_prisma_migrations, so later migrate deploy runs will fail against that database.

Upgrading a database that was created with prisma db push

Tell Prisma the existing migrations are already reflected in your schema, then deploy as normal from that point on:

npx prisma migrate resolve --applied 20260127152236_multi_tenancy
npx prisma migrate resolve --applied 20260728120000_sync_schema_with_models
npx prisma migrate resolve --applied 20260801150000_inventory_lab_prisma_models
npx prisma migrate deploy

Default Credentials (after seeding)

Role Email Password
Super Admin admin@demo-dental.com Admin@123

Warning: Change the default password immediately in production.

Environment Variables

See .env.example for all available variables. Key ones:

Variable Required Description
DATABASE_URL Yes MySQL connection string
NEXTAUTH_URL Yes App URL (e.g., http://localhost:3000)
NEXTAUTH_SECRET Yes Random secret for session encryption
ENCRYPTION_KEY Yes 64-char hex string for AES-256-GCM encryption
CRON_SECRET Yes Secret for securing cron job endpoints
OPENROUTER_API_KEY No Required for AI features
SMTP_HOST / SMTP_USER / SMTP_PASSWORD No Required for email features
SMS_API_KEY No Required for SMS features

Available Scripts

npm run dev          # Start development server
npm run build        # Production build
npm run start        # Start production server
npm run lint         # Run ESLint
npm run test         # Run unit/integration tests (Vitest)
npm run test:watch   # Run tests in watch mode
npm run test:coverage # Run tests with coverage report
npm run test:e2e     # Run end-to-end tests (Playwright)
npm run test:all     # Run all tests

# Database
npm run db:generate  # Generate Prisma client
npm run db:push      # Push schema without recording a migration (dev only)
npm run db:migrate   # Create a migration from schema changes (development)
npm run db:migrate:deploy  # Apply pending migrations (setup and deploys)
npm run db:seed      # Seed sample data
npm run db:studio    # Open Prisma Studio (DB GUI)

Project Structure

dental-erp/
├── app/                    # Next.js App Router
│   ├── (auth)/             # Authentication pages (login, signup, etc.)
│   ├── (dashboard)/        # Dashboard pages (all modules)
│   └── api/                # API routes
├── components/             # Reusable React components
│   ├── layout/             # Dashboard shell, sidebar, header
│   ├── ui/                 # shadcn/ui components
│   └── imaging/            # Dental imaging components
├── config/                 # App configuration (navigation, etc.)
├── lib/                    # Utilities, helpers, AI skills
│   ├── ai/                 # AI skill definitions
│   ├── api-helpers.ts      # Auth & API utilities
│   └── prisma.ts           # Prisma client singleton
├── prisma/
│   ├── schema.prisma       # Database schema
│   └── seed.ts             # Database seeder
├── __tests__/              # Test files
│   ├── unit/               # Unit tests
│   ├── integration/        # Integration tests (API routes)
│   ├── components/         # Component tests
│   ├── e2e/                # Playwright E2E tests
│   └── accessibility/      # Accessibility tests
├── .github/
│   └── workflows/ci.yml    # CI pipeline
└── public/                 # Static assets

Testing

The project has comprehensive test coverage:

  • Unit tests — Business logic, utilities, AI skills
  • Integration tests — API route handlers with mocked Prisma
  • Component tests — React components with Testing Library
  • E2E tests — Full user flows with Playwright
  • Accessibility tests — WCAG 2.1 compliance with axe-core
# Run all unit/integration tests
npm test

# Run with coverage
npm run test:coverage

# Run E2E tests (requires running server)
npm run test:e2e

Deployment

SELF_HOSTING.md is the full guide — the short version is that you do not need a checkout, Node.js, or a build step:

mkdir -p /opt/dental-erp && cd /opt/dental-erp
curl -fsSLO https://raw.githubusercontent.com/abinauv/dental-erp/main/docker-compose.yml
curl -fsSL  https://raw.githubusercontent.com/abinauv/dental-erp/main/.env.production.example -o .env
# fill in .env, then
docker compose up -d

That pulls a published multi-architecture image (linux/amd64 and linux/arm64) from ghcr.io/abinauv/dental-erp, waits for MySQL, runs the database migrations as a one-shot container, and starts the app. Add -f docker-compose.caddy.yml for HTTPS with automatic certificates.

SELF_HOSTING.md also covers backups and restores, upgrading, and what to do when something is wrong.

Running the image directly

docker run -p 3000:3000 --env-file .env -v dental-uploads:/app/uploads   ghcr.io/abinauv/dental-erp:latest

Mount a volume at /app/uploads. On the default STORAGE_DRIVER=local, uploaded files — patient documents, scans, signed consent forms — are written to the container filesystem. Without a volume they are destroyed the moment the container is replaced, which is every single redeploy. The -v flag above is not optional in any deployment you care about.

Already running without one? Copy your files out before you next redeploy:

docker cp <container>:/app/uploads ./uploads-backup

then recreate the container with the volume mounted and copy them back. Setting STORAGE_DRIVER=s3 removes this whole class of problem by getting uploads off the container filesystem — see docs/STORAGE.md.

Running the image this way does not migrate the database. The image carries the Prisma CLI so it can do that itself:

docker run --rm --env-file .env ghcr.io/abinauv/dental-erp:latest   node node_modules/prisma/build/index.js migrate deploy

Health checks

Two endpoints, and the distinction between them matters:

Endpoint Purpose Checks the database Use for
/api/health Liveness No "Is this process alive?"
/api/ready Readiness Yes "Should this instance get traffic?"

Point liveness probes at /api/health and readiness probes at /api/ready. Pointing a liveness probe at /api/ready means a brief database outage will make your orchestrator kill and restart otherwise-healthy containers, turning a short blip into a restart loop. /api/ready returns 503 when the database is unreachable — it never throws.

The image carries a HEALTHCHECK against /api/health, so docker ps reports container health with no extra configuration.

Manual

npm run build
npm start

Environment Requirements

Deploying from the published image, all you need is Docker Engine 24+ with the Compose plugin. Building or developing from source needs:

  • Node.js 20+
  • MySQL 8.0+ (with a dedicated database)
  • Reverse proxy (nginx/Caddy) for HTTPS in production — docker-compose.caddy.yml is a working example
  • A persistent volume mounted at /app/uploads

Documentation

  • Self-hosting — running DentalERP on your own server from a published image, with backups, TLS and upgrades.
  • Infrastructure Roadmap — how DentalERP is packaged and deployed, and what is planned next. Feedback welcome, especially on the phases not yet built.
  • File storage — local disk vs S3, and how to move between them without losing files.
  • Localization — locale support and the message catalogue.

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Security

If you discover a security vulnerability, please follow our Security Policy. Do not open a public issue for security vulnerabilities.

License

This project is licensed under the MIT License — see the LICENSE file for details.

Acknowledgments

About

Free, open-source dental hospital management system for India. AI-powered, GST billing, patient portal, tele-dentistry. Built with Next.js 16 + Prisma + MySQL.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages