Database platform: $25/month
Hiring platform: $7,491 / year
What are the best ATS platforms on the market? Anything open source?
113.6KViews
原始链接: https://www.saj.ad/2026/ats
## 申请人追踪系统 (ATS) 的困境 尽管已经历经数十年,人力资源技术领域却出奇地停滞不前。这源于利益错位:买家(专注于合规和法律的人力资源领导者)不是使用者(招聘人员),导致像Workday这样设计糟糕、复杂的系统出现。虽然 Lever 和 Greenhouse 等早期参与者曾显示出潜力,但监管和缺乏可衡量的投资回报阻碍了创新,使得现有厂商得以维持其主导地位。 构建更好的 ATS 是一个陷阱。创始人面临着一个选择:要么创建招聘人员喜欢但高管不会购买的产品,要么追逐需要无尽集成的企业交易。许多现有解决方案要么是企业级的噩梦,要么是过时的“花哨”选项,要么是现有系统的扩展,而不是替代品。 作者构建 ATS [ahire.com](https://ahire.com) 的经验,突出了关键的设计原则:强大的数据模型(处理复杂的职位结构和候选人重复数据),单仓库架构,以及通过模板化优先实现无缝入职。尽管构建了一个更优秀的产品,但挑战依然在于说服一个习惯于功能障碍的市场,更好的解决方案值得切换。 最终,机会在于重建基础,就像 Bun 对 Node.js 所做的那样——不是等待现有系统崩溃,而是提供一种从根本上改进的替代方案,尽管存在高昂的转换成本和根深蒂固的现有厂商。
February 2026⸱AI Summary
Everyone's applied to a job and felt their resume disappear into the void. That experience isn't an accident. It's the result of decades of misaligned incentives, lazy buyers, and a market that's never had to compete on the basis of product quality. This is a breakdown of why applicant tracking systems are structurally broken, why building one is a trap most founders don't see coming, and what I learned building one anyway.
Database platform: $25/month
Hiring platform: $7,491 / year
What are the best ATS platforms on the market? Anything open source?
113.6KViews
HR technology has always felt like a field that great designers and engineers avoided. My original thesis was simple: it has a talent problem. If fintech, which is a "boring" and regulated field, could attract exceptional builders, HR should have been able to as well. And yet there aren't many examples to point to.
Inversely, the domain experts in the field (namely HR professionals with deep knowledge of the industry) are often not technical or design-focused, even when their title is "Head of Technology." This lack of care for craft has persisted for decades, and you can feel it in every interface, every workflow, every nine-click process — nowhere more than Workday.
But I don't think it's quite right to say the best talent never showed up. In recruiting, Lever and Greenhouse were genuinely design-forward products when they launched over a decade ago. Recruiters who had suffered through a generation of Taleo or older Workday migrations know because they felt the difference immediately.
What actually explains the stagnation is something less flattering and more structural, and it might have to do with the buyers.
If you've ever procured an HR tool for a company, you know what really drove the purchase: legal and compliance.
A common argument I've heard from people in the field is that compliance is the chokehold for innovation (and a big reason enterprise companies don't build HR tools in-house, but that's a topic for another day).
Consider NYC's Local Law 144, which requires any AI in recruiting to have a public bias audit. This is just one city's law out of many cities, states, provinces, countries, and one European Union:
Local Law 144 of 2021 regarding automated employment decision tools ("AEDT") prohibits employers and employment agencies from using an automated employment decision tool unless the tool has been subject to a bias audit within one year of the use of the tool, information about the bias audit is publicly available, and certain notices have been provided to employees or job candidates. (nyc.gov)
But regulation alone doesn't quite explain the stagnation. Remember that banking and finance are among the most regulated industries on the planet, yet the defining fintech companies of the past decade (Stripe, Brex, Ramp, Mercury, etc.) built exceptional products inside those constraints.
The difference is that fintech had a wedge where founders could personally feel the pain of expense reports and business banking, the buyer and the user were often the same person, and the ROI of "better software" was measurable.
In HR, they almost never are, and regulation ends up serving as a moat that protects the "industry leaders" rather than a forcing function for better products.
I'm researching application tracking software and the landscape is pitiful. Terrible tools, horrible-looking job pages, and really basic stuff breaking, like requesting a demo (because of course there's not any public pricing). Is anyone building a better ATS?
30.8KViews
Try this exercise: Google "best ATS" and walk through the minefield. Try finding pricing for half the products. Sign up for free trials where you can.
I spent a few days doing this, and to no one's surprise, most of the software is carelessly stapled together by founders and developers who have never recruited in a real "recruiter" role. And if you've had the misfortune of sitting through any sales calls, you'll see that the products are often tailored toward leaders and not the recruiters who live with the product.
Enterprise SaaS generally suffers from the dysfunction Buyer ≠ User, and HR technology is a textbook offender.
There are a few reasons for this. The main one is that HR is a cost center and generates no revenue, which gives HR leaders less leverage, even in companies where C-Suite prioritizes investing in recruiting top talent. Every dollar spent on HR software is scrutinized as pure cost, not investment.
Compare that with a CRM purchase for sales, where the ROI conversation starts from an assumption of value. In HR, executives buy software to optimize for board-ready metrics and compliance coverage, while recruiters just want to know if they can do their job. The goals don't overlap, and the product reflects it.
Much like the typical tarpit ideas, building recruiting products is a trap.
Most founders are forced to choose between building something recruiters love that executives won't buy, or winning enterprise deals.
Scroll through the top 100 applicant tracking systems in your search results and you'll find three broad categories:
But beyond those three, a fourth, more interesting pattern emerges, and it's where the market's misalignment is clearest: software that exists purely to exploit Workday-locked enterprises. These companies pitch themselves as "intelligence platforms" (vaporware, in my experience), tout "first-class" Workday integration, and carry billion-dollar valuations you probably haven't heard of. The product is the sales demo that impresses VPs. Meanwhile, recruiters are still shuffling candidates around in Google Sheets.
This isn't an accident. The same dynamic plays out with the latest wave of "AI-native" recruiting startups that offer solutions for sourcing, reviewing, matching, scoring, or even interviewing candidates.
I low-key assumed that the thing the buyer is buying here is the "we help you source top-tier talent" nonsense. A tool can't help with that, so they pitch it as something other than a tool. And therefore create the illusion of more value.
109Views
These tools serve as an extension to your ATS. They integrate with it. That's by design, because most companies won't migrate off their existing system, and arguably for good reason. Migrations are painful, the cost of switching rarely justifies the marginal improvement, and most leaders don't fully grasp that the ATS itself is the root cause. So instead of fixing the foundation, they bolt on another "solution." More tools, more complexity, more sprawl, and the same broken hiring experience for recruiters, hiring managers, and candidates alike.
The economics behind applicant tracking systems might explain why the market fails to self-correct on many levels. Take, for example, a 50-person company with 5-10 open roles year-round. The company can justify spending $12,000/year for Greenhouse, even if it's objectively overpriced for the use case and the tool is subpar. $1,000/month is a rounding error compared to the $300k+ salaries they're offering.
For founders, this means you can't win on product quality alone. A 10x improvement is needed just to overcome the apathy that comes with the market, and typically this means going beyond the core "ATS" layer and building out things like a CRM for lead management, a scheduling suite, and an analytics product. This is exactly the approach Ashby has taken. Or conversely, Gem, which built a recruiting CRM first and launched an ATS years later, working backwards toward the same conclusion.
However, even if you do win customers on the premise of cheaper and better software, the revenue model fights you. Unlike sales tools where spend scales with revenue, ATS pricing is typically based on company headcount, and the biggest customers in the market already have an ATS tangled into their enterprise HRIS of choice, which means the prized customers are stuck. And even if you pivot upmarket toward enterprise, the product will become mired in integration complexity and never really gets used like the core ATS layer.
I watched these dynamics play out firsthand a few years back when a YC company launched with the classic pitch: ATS + CRM all-in-one. I got on a sales call to procure it for a small company, and they told me they were pivoting into a recruiting CRM for agencies.
We were looking for something simple that they seemed to offer, a modern job board and candidate tracking with some bells and whistles. They brought exactly that to the market. But they rejected us as a customer mid-sales-call by saying, "It's too hard to build an ATS". I took that to mean that it was too hard to sell an ATS.
Most products are not degraded by one single thing. Products turn out as bad as the cumulative papercuts they've self-inflicted. Bad design at the data modeling level compounds into ineffective workflows at the UI, and all of it is made worse by a market that pits buyers against users.
And there's another thing. Much of recruiting is misunderstood as an administrative function when it's actually closer to sales. The work is made up of phone calls, team handoffs, record sharing, shortlisting, and back-pocketing of names. It lives in people's heads, quietly squirreled away into personal spreadsheets and hiring manager Slack channels — the result of decades of bad habits built on bad foundations exacerbated by stagnation.
The only way out is better foundations. What follows is what I learned building a production ATS from scratch: the data models, architectural decisions, and edge cases that compound into either a good or broken system. But it's not an instructional guide. It's more about product thinking and system design, and it's intended for a niche audience of people in recruiting tech. You can skip to the conclusion if you'd like.
How you approach building software philosophically matters as much as the technical decisions, especially when building for a specific user base like HR professionals. The compass I've followed is simple — to make onboarding as close to non-existent as possible. In a recruiting tool, there's a lot to configure before the system works (pipeline stages, application forms, interview feedback templates, departments, locations, and more).
Not always, but often, the need for onboarding implies complexity. The product should feel logical and easily discoverable by way of its design. The first time someone enters the product, exploring it should feel seamless, like pulling a thread to find the edge of the fabric, rather than mentally tracing a maze where every turn might be wrong.
In practice, everything in the system is abstracted into a template. Every lever of configuration is therefore reusable and centrally managed — so recruiting operations teams can "centrally command" the product with ease, where one change cascades across the entire tool.
For example, imagine creating a job and having to define the stages. Instead, you can force the use of templates to shape behavior, so that every decision is justified and encourages reusability.
Creating 1,000 jobs over time, and having the ability to customize stages at the job level might feel easier for the user, but it feels like a maze at scale. Compare that to the experience of viewing a job and it satisfyingly pointing you to the template where you can make the changes centrally, this feels like pulling a thread.
As with anything, there are exceptions to this rule. Having seen recruiting at scale, users should be compelled to think about how they can share resources and justify any deviation that arises.
The first technical order of business is building a monorepo. There's often a tax that comes with this, but for an ATS, the pros outweigh the cons (Turborepo solves the usual pain points around incremental builds, environmental variables, typechecking, etc.).
The main goal is to maintain separation between your main app (app.example.com) and your public job board (jobs.example.com, which will ideally serve millions of candidates), while sharing the schema, types, and business logic. Reusable packages for core features (like a form builder/editor/viewer) also need to work across both apps.
apps/
├── app/ # Main ATS (Next.js) (app.example.com)
├── jobs/ # Public job board (Next.js) (jobs.example.com)
packages/
├── backend/ # Database, ORM, auth - or in my case, Convex (schema, router, http, etc.)
├── shared/ # Zod schemas, types, utils
├── form/ # A good example package: An application form builder and viewer, built in the app, rendered on the job board
At this point, your API can live within their respective apps, but in my case, I'm using Convex, so all functions are centralized on the backend package and hosted on an external URL which I've pointed to api.example.com.
Consider a simple question: out of millions of potential records, how do you reliably identify candidates graduating in 2026? Or in June 2026 specifically? Or broadly in the range of September-December 2026? The answer lives in schema design, specifically how you store education details including start and end dates. It may seem obvious, but so many systems fail to design for it.
What a well-designed data model will unlock:
Candidates, but should be given access to "B.S. in Computer Science" from CandidateEducationAssignments.Jobs appear deceptively simple. You might think, create a jobs table with a published boolean, and expose any jobs that are true to the job board. If you find an ATS with this architecture, you should run away.
Jobs are three dimensional in many cases, especially for companies with high volume and regional complexity.
Go to any big tech company's job board and search for "Account Executive." You'll find 30+ variants covering different locations (SF, NYC, London), grade levels (IC4-IC8), industries (retail, healthcare, government), and markets (SMB, mid-market, enterprise).
There are two primary solutions you can implement:
❌ 2D Architecture: Parent job, child openings
A recruiter creates one parent "Account Executive" job that's always published. Candidates apply to this single posting, and recruiters manually attach each application to the actual opening it should belong to.
(Job) Account Executive - SMB [Published]
└── Candidates apply here, then manually moved to internal requisitions:
├── (Job) AE - SMB SF - Sarah Chen, VP Sales [Private]
└── (Job) AE - SMB NYC - Marcus Rodriguez, Director Sales [Private]
In systems like Workday, this means moving candidates from the public evergreen job to other private child job requisitions that represent real seats with hiring manager, location, headcount, and approval. This keeps the job board relatively clean, but creates pipeline chaos internally: thousands of applications landing in one bucket that need constant manual triage and reassignment.
✅ 3D Architecture: Parent job, child postings, optional openings
When compared with the typical "create and publish a job directly", this feels counterintuitive. However, jobs should be private and never publishable. Instead, job postings should "branch" off the parent — with the ability to publish to the job board.
Here's what it would look like: a recruiter creates an "Account Executive (AMER)" parent job that groups multiple possible roles planned to be hired in the next year. Each unique role can be published as child postings, e.g. "Account Executive - Enterprise, SF" or "Account Executive - SMB, NY."
Candidates self-select into the proper job posting based on the title and job description. Applications roll up to the parent, so recruiters see everything in one view and filter by posting.
This reduces the chaos of hundreds of varying parent jobs into dozens of parent jobs with their own hierarchy of public or internal postings.
The recruiter can then create job openings — the actual approved seats with hiring manager, start date, budget code, and approval chain. The recruiter can attach openings to applications as they advance (to offer or hire stage).
Three layers: parent jobs (recruiter-facing), postings (candidate-facing branches), openings (optional seats for advanced companies). This is maximum flexibility, and every company can self-select the degree of complexity they require.
(Job) Account Executive - AMER
├── (Posting) Account Executive - Enterprise, San Francisco [Published]
│ ├── (Opening) Enterprise SF - Team A [Optional]
│ └── (Opening) Enterprise SF - Team B [Optional]
├── (Posting) Account Executive - SMB, New York [Published]
└── (Posting) Account Executive - Mid-Market, Seattle [Published]
(Job) Account Executive - EMEA
├── (Posting) Account Executive - Enterprise, London [Draft]
│ ├── (Opening) Enterprise London - North [Optional]
│ └── (Opening) Enterprise London - South [Optional]
└── (Posting) Account Executive - Mid-Market, Berlin [Published]
The hierarchy of Jobs → JobPostings → JobOpenings is clear now, and their schemas easy to piece together.
Account Executive, Mid-Market
Published • Job Board
Account Executive, Mid-Market - San Francisco
Account Executive, Mid-Market - New York City
Draft
Account Executive, Mid-Market - Chicago
Full Time
Backfill
1 Headcount
Mary O'Brien Backfill
Remember, job openings are optional, but they are critical for creating a "3D" architecture.
A job opening represents a specific seat which belongs to a team or hiring manager and usually has an approval chain connected to it to satisfy compliance. If there are two seats open for one team with the same approvals and budget, then the job opening can have its headcount incremented.
How the job opening can be used is another question. It can be attached to a job directly; this way the job is "compliant" and has proof there are seats open to fill.
Eventually when job applications come through, the job openings will need to be tied to the application for which an offer is extended. In this case, a job application can be linked to a jobOpeningId to "fill" the available headcount.
Alternatively, if you build a standalone Offers table to track all job applications where an offer was generated, the job opening can be linked to the offer directly instead. Either approach works, depending on the complexity of the application.
One issue to keep in mind is that job postings can be assigned to not just one job board, but multiple. Eventually, big enough companies need an internal job board with SSO access. A job can then be posted externally and internally. Or if a company is large enough, they might have multiple job boards based on their acquisitions, e.g. Microsoft bought Activision but still maintains a separate brand identity and job board.
Therefore, JobPostings must be linked to one or more JobBoards. This can be handled with a junction table called JobBoardAssignments.
Building this upfront is worth the effort. Each tenant is given one default job board, and when necessary they can manage additional ones.
On the frontend, jobs.example.com can pull from JobBoards and neatly query all JobBoardAssignments and their related JobPostings.
jobPostings (published, not hidden, deadline check)
→ jobPostingBoardAssignments (filter by jobBoardId)
→ jobPostingLocationAssignments → jobLocations
→ jobs → jobCategoryAssignments → jobCategories
Duplicate profiles are extremely common in recruiting systems. A candidate might apply with a second email to "start fresh", or a university student might apply twice, once with their personal email, another time with their .edu email.
The candidate record should have primary identifiers that make it easy to "de-duplicate" them. This means including a primaryEmailAddress and optionally a linkedInUrl (which oftentimes is more reliable than an email address).
The candidate profile might collect multiple email addresses over time from an application or an event sign-up. Besides the primary email address, you should store additional email addresses in an object (e.g. additionalEmailAddresses) or a separate table like CandidateEmailAddressAssignments.
Importantly, each Candidate is technically a lead (and your ATS is technically a talent CRM) and each candidate can have JobApplications attached to them. That means a recruiter can create a "candidate" (a person who is in candidacy for a job) before their job application, or a candidate can come from an event or resume list. It's also worth emphasizing that even if a candidate has 10 job applications, they could all be two years old and rejected, so the candidate is once again considered a lead (and former applicant).
Moreover, the job application is not just a log of applications, but also an auditable snapshot of the candidate's name and email address at the time of the application, even if the candidate record values differ and evolve over time. It's not uncommon for someone to apply with a nickname, e.g. first name "Rich" in the job application, only for their candidate name to be revised to "Richard" for offer generation.
This setup is ultimately an example of simplicity that keeps the door open for complex use cases, like temporal audits.
jobs // Parent job (internal)
├── jobPostings // What candidates see (references jobId)
│ ├── jobApplications // Applications from job board (references jobPostingId)
│ └── jobBoardAssignments // Junction: jobPostingId → jobBoardId
└── jobOpenings // Approved seats (references jobId)
└── jobApplications // Can optionally reference jobOpeningId when advanced to offer or hire
jobBoards // External careers site, internal portal, etc.
└── jobBoardAssignments // Junction: connects jobPostings to jobBoards
candidates // Candidate profiles (can have multiple)
└── jobApplications // References candidateId, jobPostingId, optional jobOpeningId
Jobs and candidates are the basis of an ATS, but there's plenty more to build. Think through every other entity with the same rigor that produced the schemas and components above and you'll find yourself building with intention and taste that will not only be worth using, but worth switching to.
The same dysfunction that makes an ATS painful to use is what makes it painful to replace — buyers have lived with the broken thing long enough that the broken thing stopped looking broken.
You can solve the data modeling, clean up the pipeline UX, eliminate the spreadsheet smuggling, and make onboarding invisible, and still find yourself in a room that has already decided the problem isn't worth solving.
Which is exactly why it's worth building anyway. Perhaps the most instructive lesson here might be what Bun did to Node.js. Node isn't broken. It's the de facto JavaScript runtime with near-universal adoption. But Jarred Sumner rebuilt it on a different architectural foundation, made it significantly faster, and shipped it. He didn't wait for Node to fail or simply accept what the market had decided was the winner. Incumbency was the argument for building, not against it.
HR is a construct of regulation and bureaucracy, and AI emergence makes it stickier, not less so. The switching costs, the procurement cycle, the buyer who never uses the product — these are the conditions that suppress the market's ability to self-correct. The incumbents are protected by the dysfunction and not threatened by it.
But what AI has also done is collapse the cost to build. It's never been cheaper or faster to build software that could do for HR and recruiting what fintech did to business banking.
If you're interested in a demo, check out ahire.com.