freehire: a self-hostable job search engine that crawls company ATS pages directly
freehire — the open-source search engine for job seekers
At a glance
- What is it?
- freehire is an MIT-licensed Go application that crawls company career pages across 92 ATS platforms, normalizes listings into one schema, and serves faceted search from Meilisearch. It is a full stack to operate, not a library to import.
- Who is it for?
- Adopt freehire if you want a job catalogue you control and you are willing to run six services (api, web, postgres, meilisearch, redis, minio) plus a crawler fleet, or if you are building a product on top of a keyless HTTP API. Do not adopt it if you want a hosted search box with no infrastructure, if you need non-IT job categories, or if you cannot operate Postgres with pgvector and Meilisearch side by side.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The repost problem freehire is built around
Job boards inherit their listings from other job boards. A role posted on a company's Workday tenant gets copied to aggregators, re-titled, sometimes re-dated, and the copy outlives the original. The README frames freehire against exactly that: every listing is crawled directly from a company's own ATS and links to the original posting, with the claim of no recruiter reposts, no aggregator middlemen, no dead links. The audience is narrow and specific. This is an IT job catalogue. The README says every IT job, and the facets it names (work mode, seniority, skills, salary) are software-industry facets. A hospital recruiting nurses, a logistics firm hiring drivers, or a retailer staffing stores will not find their categories here. The secondary audience is developers: the repository ships a keyless public API, a separate CLI repository, an MCP server for Claude Desktop and Claude Code, a browser extension for form filling, and ChatGPT Actions. If you want to build an application on top of a job corpus rather than read one, the API is the entry point.
Crawl, normalize, deduplicate, index: the pipeline as the README describes it
The stated scale is 3.3M+ live postings from 294,000+ companies across 92 ATS platforms and 225 live sources in all, counting aggregators and direct feeds alongside the ATS platforms. Each source is configured in YAML; the README says adding a company is one line of that file. The pipeline has four visible stages. Crawling pulls postings from ATS endpoints (Workday, Greenhouse, Lever, Ashby, iCIMS and a long tail). Normalization maps each platform's payload into a single posting shape. Deduplication collapses the same role posted to three boards into one entry, keyed on what the README calls a stable key. Indexing writes the normalized records into Meilisearch for full-text and faceted search, while PostgreSQL with pgvector holds storage, filtering and semantic embeddings. Facet values come from curated dictionaries rather than inference, which is the design decision that keeps seniority and skills filters from drifting as new postings arrive. The stack is Go with Fiber v2 for HTTP, sqlc for type-safe SQL instead of an ORM, langchaingo for LLM access over any OpenAI-compatible endpoint, Bifrost as an LLM gateway with per-user virtual keys and cross-provider fallback, and Langfuse for call tracing. Redis handles rate limiting and realtime fan-out; S3-compatible object storage holds CVs, headshots and previews.
Running it: make up, health check, and the volume trap
The quick start is short. make up builds and starts the whole stack in Docker: api, web, postgres, meilisearch, redis, minio. Two curls confirm it: curl localhost:8080/health and curl localhost:8080/api/v1/jobs. If port 8080 is taken, HIRE_HOST_PORT=8090 make up moves the host port. For lighter work, docker compose up -d db starts the database alone and make run starts the application against it. The trap is migrations. They are applied automatically on first Postgres volume init because the migrations/ folder is mounted into /docker-entrypoint-initdb.d, and the README states plainly that changing a migration does not re-apply to an existing volume. The recovery is either docker compose down -v && make up, which destroys the volume, or make migrate to apply pending files by hand. Anyone who edits a migration and wonders why the schema did not change has hit this. It is a normal consequence of using the Postgres init hook as a migration runner, and it means schema evolution on a populated instance is a manual operation.
The application layer is larger than the search engine
The repository does not stop at a catalogue. Under the heading Beyond the catalogue it describes four more surfaces built on the same data. Find covers faceted search, curated collections, saved searches with email and Telegram digests, shared boards, market analytics and something called the ghost-job signal. Apply covers a CV builder with ATS-safe PDF templates, deterministic CV-to-vacancy scoring, AI fit analysis, CV tailoring that the README says invents nothing, tracer links and referrals. Track is an application board with stages, a mail inbox that links recruiter replies to the application they answer, an append-only event ledger and reminders. Ask is an in-process agent with five presets (chat, browse, profile, CV tailoring, interview rehearsal) that the README says runs with no shell and no minted credential. The linked docs/features.md is where each feature's location in the tree and its LLM dependency are documented; the README itself only flags that some features need an LLM endpoint configured and some draw on AI credits. That is a lot of surface area for one repository, and it is the main reason the operational footprint is what it is.
Where freehire is the wrong tool
Self-hosting is the point and also the cost. Search runs on Meilisearch, storage and embeddings on PostgreSQL with pgvector, rate limiting on Redis, files on S3-compatible storage, and the frontend is a SvelteKit server under web/. That is six services before you crawl anything, and the ingest side is not free either: Prometheus via the node_exporter textfile collector and Grafana exist specifically to watch ingest and LLM infrastructure, which tells you the maintainers consider that infrastructure worth monitoring. If you want a search box and nothing else, this is the wrong shape. Two further boundaries are worth stating. First, the README does not describe crawler failure handling, retry policy, or what happens when an ATS changes its response format; the coverage claim of 92 platforms implies ongoing maintenance against each one, and the repository gives no per-source health reporting that this material describes. Second, the licence is MIT for the code, which says nothing about the job postings themselves. Redistributing crawled listings from company career pages is a separate question the README does not address, and it is the first thing to resolve before running a public instance.
How it differs from scraping with your own scripts
The obvious alternative is a hand-rolled scraper plus a search index: a few Python files per ATS, a Postgres table, maybe Elasticsearch or Meilisearch in front. That approach gives you total control of the schema and no dependency on someone else's normalization decisions. What it does not give you is the part freehire has already paid for: 92 ATS integrations, a single normalized posting shape, and a deduplication key that collapses cross-posted roles. Writing a Workday crawler is an afternoon; keeping 92 of them working as vendors change their APIs is a standing commitment. The other alternative is a hosted job API, which removes the infrastructure entirely but reintroduces the intermediary the project exists to avoid, and typically restricts how you may republish results. freehire sits between those two: more infrastructure than an API key, less maintenance than owning every integration yourself. The trade is that you inherit its schema, its facet dictionaries, and its release cadence.
Maintenance, releases, and what MIT does and does not cover
The release history visible here is the browser extension, not the server: extension-v0.1.2, v0.1.5 and v0.1.6 between 15 and 17 August 2026, with the last push to main on 10 September 2026. The core application does not appear to be versioned through tagged releases in this material, so self-hosters tracking main are tracking a moving branch. The stack pins are the maintenance surface: Fiber v2, SvelteKit 2 with Svelte 5 runes, Tailwind 4, sqlc, pgvector, langchaingo. Upgrades to any of those land in your deployment when you pull. The LLM side adds a second cost centre: Bifrost tracks per-user spend and Langfuse traces calls, and the README distinguishes features that need an LLM endpoint from those that draw on AI credits, so a self-hosted instance without an LLM endpoint configured loses the Apply and Ask surfaces rather than failing outright. On licensing, MIT covers the code in this repository. It does not grant rights to the crawled postings, and it does not cover the separately hosted CLI, MCP server or extension repositories, which carry their own terms. Treat the data question as unresolved by the licence file.
Editorial conclusion
Adopt freehire if you want a job catalogue you control and you are willing to run six services (api, web, postgres, meilisearch, redis, minio) plus a crawler fleet, or if you are building a product on top of a keyless HTTP API. Do not adopt it if you want a hosted search box with no infrastructure, if you need non-IT job categories, or if you cannot operate Postgres with pgvector and Meilisearch side by side. Verify first: whether the ATS platforms you care about are among the 92 covered, how the crawler behaves when a source changes its markup, and whether the MIT licence on the pipeline covers the job data you intend to redistribute.
Community notes