freehire is a job data platform with a candidate workspace attached
freehire starts with a crawler and normalization pipeline rather than a blank job-board CMS. Source adapters pull listings from applicant-tracking systems, company career pages, and selected aggregators. Postgres keeps the system record, while Meilisearch serves full-text and faceted results. On top sit saved searches, CV editing, job matching, application stages, mail handling, notifications, and an in-process assistant. The public API exposes the catalogue without a key.
The README reports 3.3 million open postings from 294,282 companies and 225 live sources. Those are the project's current catalogue figures, not counts our sandbox reproduced. That distinction matters because collection freshness is part of the product. A developer can use the hosted API without operating the crawl, but a self-hoster must populate data, schedule each source, drain indexing queues, and decide how closed listings leave the catalogue.
The local stack runs seven Compose services
The quick start launches database, search, cache, object storage, storage initialization, API, and web services through Docker Compose. Postgres also needs pgvector, and the web application is a SvelteKit package linked to a sibling design system. The Go server handles request-time work, while most crawling, enrichment, indexing, notification, and backfill jobs run once and exit for an external scheduler to invoke again.
That is substantial ownership for a job-search tool. Our checkout contained 6,555 files, about 466,086 source lines, and 50 MB before any service image or data volume existed. Backups must cover candidate records, applications, CV assets, and the catalogue. Meilisearch has its own rebuild and swap process. Redis supports rate limits and fan-out, while MinIO supplies the local S3-compatible path. A single-container hobby deployment is not what this repository describes.
What happened when we ran it
Our run at commit 36828fe executed the root pnpm install in 7 seconds. It installed 0 packages and occupied 1 MB because the root package.json only identifies the project and pnpm version. The repository contains separate frontend packages plus a Go backend, so this successful command did not fetch their dependencies, compile them, launch Docker Compose, apply migrations, or request the health endpoint.
The root manifest had no build script or target, so the build step was skipped. It also had no test script or target, so tests were skipped. The repository does contain Go test files and 7 CI workflow files, but our supplied lab run did not execute them. It would be false to describe this as a passing build or test result. The harness only proved that the nearly empty root Node install completed.
Our scan found a Dockerfile and Compose file, which match the documented deployment route. A deeper operational trial would need to start all services, verify localhost:8080/health, ingest a controlled board file, drain search writes, and compare API results with the source. None of those actions occurred in this sandbox measurement, so the hosted catalogue claims and runtime behavior remain outside our lab evidence.
Required secrets are small at first and expand with features
The server requires JWT_SECRET, and the default local database URL points at Postgres. Docker Compose supplies local Meilisearch, Redis, and MinIO plumbing. OAuth providers, inbound email, remote S3 storage, LLM calls, speech transcription, tracing, and notification delivery each add their own settings. The README says optional features stay disabled when their credentials are absent.
Migrations have a specific trap. Compose mounts them into Postgres initialization, so they apply automatically only when the volume is new. Editing a migration does not change an existing database. The documented choices are to apply pending files manually or recreate the volume, which destroys local database contents. With 466,086 source lines and many workers reading the schema, production changes need an explicit migration sequence rather than reliance on first-boot behavior.
Run-once workers replace one background job service
The API server does not perform crawling, bulk enrichment, or index maintenance in its request process. Commands under cmd/ crawl individual provider files, drain enrichment and embedding queues, rebuild search, capture application forms, send notifications, and perform backfills. Postgres outbox rows coordinate those processes. This isolates slow providers and lets each schedule differ, but the operator must supply cron or another scheduler and notice nonzero exits.
The README says prune is the only hard-delete path and defaults to dry-run. That is a sound safety choice, although it does not solve stale data by itself. Open issue 2017 reports live rows that had not been seen for more than 3 days across several providers, including complete stale shares for two sources in the issue's production query. The report was still open when fetched, so catalogue users should inspect last-seen data and provider health.
Search is fast because Meilisearch holds the full public job shape
Search results can render without a Postgres round trip because the index stores the public job representation. A full reindex builds a replacement and swaps it atomically. Incremental writes pass through an outbox so many source crawls can become fewer Meilisearch updates. The architecture document also warns that deploying a new filter before its index setting can turn a Meilisearch 400 into a failed filtered page.
Facet quality still depends on classification choices. Issue 2088 says companies without a curated industry can inherit an overly broad union of domains from their open postings. Its production analysis found 9,989 companies with at least 3 domains and no curated industry. The proposed threshold needs a materialized field and company reindex. Until that work lands, consumers using industry filters should sample results rather than treating the facet as ground truth.
Current activity is high, while the latest tag covers the extension
GitHub recorded the last push on August 25, 2026, with 487 stars and 64 combined issues and pull requests. The latest release endpoint returned extension-v0.1.6, published August 17, 2026. That tag concerns the browser extension rather than a versioned release of the entire platform. The repository's issue activity includes source requests, interface work, catalogue defects, and operational investigations.

