Frappe HR (formerly the ERPNext HRMS module) was spun out as a standalone app in 2023. Same doctype engine, same REST + RPC surface, but without requiring the full ERPNext manufacturing and accounting stack. It covers employees, payroll, leave, attendance, expense claims, performance reviews, and recruitment — all as standard Frappe doctypes you can query, extend, and hook into.
For years, HR management in the Frappe ecosystem meant installing all of ERPNext — accounting, manufacturing, stock, CRM, and the HR module bundled together. In 2023, the Frappe team extracted the HR doctypes into their own app: Frappe HR (also called HRMS). You can now install it alongside ERPNext or standalone with just the Frappe Framework.
The app is still young as a standalone product. The extraction was clean — the doctypes are the same ones that ran inside ERPNext for years — but the independent release means some edges are rough. Documentation assumes ERPNext context in places, and a few features (like payroll accounting entries) still need ERPNext installed to work fully. Be honest with yourself about whether you need the standalone or the full stack.
If your organisation needs HR but not manufacturing, stock, or purchasing, Frappe HR lets you skip the ERPNext overhead. You get the same employee records, leave management, payroll engine, and attendance tracking — without the 400+ doctypes that come with the full ERP. Install it on a clean Frappe bench, or alongside ERPNext if you already run it.
Every object below is a standard Frappe doctype — queryable via REST, hookable via hooks.py, introspectable via frappe.get_meta().
| Doctype | Purpose | Key fields |
|---|---|---|
Employee | The master record for a person in the org | employee_name, department, designation, status, company |
Salary Structure | Template defining earnings and deductions | payroll_frequency, earnings (child table), deductions (child table) |
Salary Slip | One payroll run for one employee | employee, gross_pay, total_deduction, net_pay, posting_date |
Leave Application | Employee request for time off | employee, leave_type, from_date, to_date, status |
Attendance | Daily presence record | employee, attendance_date, status (Present/Absent/Half Day/On Leave) |
Expense Claim | Employee reimbursement request | employee, expenses (child table), total_claimed_amount, approval_status |
Appraisal | Performance review cycle | employee, appraisal_template, goals (child table), total_score |
Same Frappe API surface as every other app. Authenticate with an API key, hit /api/resource/ for CRUD, hit /api/method/ for RPC.
# List active employees in a department GET /api/resource/Employee ?filters=[["status","=","Active"],["department","=","Engineering"]] &fields=["name","employee_name","designation","date_of_joining"] &order_by=employee_name asc &limit_page_length=50
# Fetch a single salary slip with all child-table rows GET /api/resource/Salary Slip/HR-SAL-2026-00042 # Create a leave application POST /api/resource/Leave Application { "employee": "HR-EMP-00012", "leave_type": "Annual Leave", "from_date": "2026-05-01", "to_date": "2026-05-05", "reason": "Family holiday" }
# RPC: get leave balance for an employee POST /api/method/hrms.hr.doctype.leave_application.leave_application.get_leave_balance_on { "employee": "HR-EMP-00012", "date": "2026-04-16", "leave_type": "Annual Leave" } # RPC: mark attendance in bulk POST /api/method/hrms.hr.doctype.attendance.attendance.mark_attendance { "employee": "HR-EMP-00012", "attendance_date": "2026-04-16", "status": "Present" }
The primary 2nth selection filter. Frappe HR scores a conditional yes — the REST API is a genuine, first-party, agent-addressable surface; the MCP story is community-only and needs care, because this is a payroll-bearing, POPIA-relevant data store.
REST API — the stable, first-party surface. Every doctype (Employee, Leave Application, Salary Slip, Attendance) is exposed via the Frappe REST API with an API key/secret — no bespoke endpoints, no custom integration layer. This is the contract to build an agent against: it's versioned with the framework, documented, and the same surface every other Frappe app uses. Prefer it.
MCP — community only, no first-party server. Neither frappe/hrms nor frappe/frappe ships an official MCP server. Several community servers wrap the Frappe/ERPNext REST API (and therefore cover HR doctypes), at varying maturity:
| Community MCP server | Shape | Caution |
|---|---|---|
buildswithpaul/Frappe_Assistant_Core | Frappe app; OAuth 2.0 + PKCE, per-user permission scoping, audit log | Most production-shaped; verify licence + maintenance |
mascor/frappe-mcp-server | Frappe app; DocType/operation allowlist, field-level control, audit logging | Security-conscious; small project — verify maintenance |
rakeshgangwar/erpnext-mcp-server | TypeScript; erpnext://{doctype}/{name} resource URIs | Generic ERPNext wrapper |
Casys-AI/mcp-erpnext | npm package; ~120 tools across 14 categories | Broad surface — evaluate against least-privilege |
vyogotech/frappe-mcp-server | Go; generic any-DocType, any OpenAI-compatible LLM | Generic |
Treat the REST API as the stable agent contract. Use a community MCP server only with explicit DocType allowlisting, per-user permission scoping, and audit logging — the Frappe_Assistant_Core and mascor designs are the right shape. Never grant an agent blanket DocType access to a system that holds salaries, banking details, and performance records. This is POPIA-relevant personal information; the agent surface must be scoped, audited, and lawful-basis-documented. Evaluate any community server's licence and maintenance before factory adoption.
Salary Slips can be created standalone, but the accounting journal entries (GL entries) that post payroll to the ledger require ERPNext's accounting module. Without it, payroll runs but doesn't hit the books.
Employees don't get leave balances just because a Leave Type exists. You need to create Leave Allocation records — either manually, via Leave Policy Assignment, or through the leave allocation scheduler. Miss this step and every leave application will fail validation.
A Salary Structure alone does nothing. You must create a Salary Structure Assignment linking the structure to a specific employee with an effective date. No assignment means the payroll entry won't pick up that employee.
If an employee has an approved Leave Application for a date, the system expects no Attendance record for that day (status is implicitly "On Leave"). Creating an Attendance record for the same day can cause validation errors or inconsistent reports depending on the order of operations.
The HRMS app was extracted in 2023. Some documentation still references ERPNext paths, and community answers often assume the full ERPNext stack. When searching for help, try both "frappe hrms" and "erpnext hr" as search terms.
The honest verdict: Frappe HR is usable for South African payroll, but there is no first-party SA statutory pack. The framework gives you the mechanisms; the SARS-specific outputs are build work, not configuration.
What the framework gives you natively: configurable income-tax slabs via the Payroll Period doctype — the mechanism for SARS PAYE, which is progressive/slab-based. Salary components can model UIF (1% employee + 1% employer), SDL (1% where annual payroll exceeds R500,000), and other statutory deductions. ZAR is supported as a base currency.
What it does not ship (treat as a gap, not a feature): SARS statutory reports — EMP201 (monthly), EMP501 (annual reconciliation), IRP5 / IT3(a) tax certificates — and the SARS e@syFile / eFiling export formats. There is no maintained SA localisation app equivalent to the India localisation. These are achievable via salary components, custom reports, and the REST API / hooks — but budget a SA payroll specialist to validate PAYE/UIF/SDL math and produce EMP201/EMP501/IRP5 outputs before any production payroll run.
Frappe HR holds IDs, salary, banking, and performance data — squarely POPIA-relevant. Self-hosting on an SA region (africa-south1 / southafricanorth / af-south-1) keeps data in-country. The Cloud Run + Cloud SQL + Memorystore pattern defined for the Frappe/ERPNext deployment applies unchanged — HR is just another installed app on the same bench. Any agent or MCP access path must be scoped, audited, and lawful-basis-documented. The full SA statutory layer is tracked as a discrete build item in the biz/hr value chain, not a config toggle here.