Junior engineers tell me the same story on repeat: 150, sometimes 200+ applications before anything sticks. Five years ago, 30 thoughtful applications would land a junior a handful of phone screens. Then AI made it trivial for everyone to apply everywhere, companies responded with harder filters, and entry-level postings started drawing four-digit applicant counts within days.
You can be angry about that. I am, and I read resumes for a living. But anger doesn't change the math you're operating under, and the math says this: when a process requires 150+ attempts, memory and a messy spreadsheet stop being tools and start being liabilities.
Sales teams solved this exact problem decades ago. They call it a CRM, a customer relationship management system, and it exists because no human can run a 200-opportunity pipeline in their head. Your job search is now a 200-opportunity pipeline. Here's how to build a job application tracker that works like one.
Your spreadsheet dies around application 40
A flat spreadsheet with columns for company, role, and "status" works fine for a dozen applications. Somewhere around 40, three things break.
First, you lose the timeline. "Status: Interviewing" tells you nothing about whether the recruiter went quiet six days ago, which is exactly when a polite nudge would have helped.
Second, you lose the feedback loop. If you can't answer "what's my response rate on referrals versus job boards," you can't reallocate your hours toward what's working. You just keep spraying.
Third, you lose the artifacts. When a recruiter calls about an application from three weeks ago, you need the exact resume PDF you sent them and the posting text, which by then has usually been taken down. A spreadsheet cell that says "applied ✓" gives you neither, and walking into a phone screen without knowing what the other person is reading is how juniors flunk screens they should pass.
A sales rep would never tolerate any of these. Their CRM records every stage transition with a date, attributes every deal to a source, and attaches every document sent. Steal all three ideas.
Stages, not statuses
The core shift is from a status field you overwrite to a pipeline of stages you move through. A reasonable pipeline for a junior engineering search:
- Sourced – you found the posting, haven't applied yet
- Applied – application submitted, resume version recorded
- Screen – recruiter call or async screen scheduled
- Technical – coding challenge, take-home, or technical interview
- Onsite – final loop
- Offer
- Rejected or Ghosted – both are terminal, and both are data
Two rules make this work. Every transition gets a timestamp, because the timestamps are what power your conversion metrics and your follow-up timing. And Ghosted is a real stage you assign deliberately, not a purgatory you leave things in. My rule: no response 21 days after your last touch means ghosted. Close it, log it, reclaim the mental space. You can always reopen if they resurface.
The schema
You can build this in Notion or Airtable, but I'll show it as SQLite because half of you will enjoy that more, and because writing the schema forces you to decide what you actually track.
CREATE TABLE applications (
id INTEGER PRIMARY KEY,
company TEXT NOT NULL,
role TEXT NOT NULL,
posting_url TEXT,
posting_text TEXT, -- paste it; postings vanish
posted_at DATE, -- how fresh was it when you applied?
source TEXT, -- 'referral', 'linkedin', 'board', 'cold'
stack_match INTEGER, -- 0-100: % of required skills you have
resume_version TEXT, -- filename of the exact PDF you sent
stage TEXT DEFAULT 'sourced',
applied_at DATE,
stage_changed_at DATE,
last_touch_at DATE, -- last time YOU did something
next_action TEXT,
next_action_at DATE,
notes TEXT
);
CREATE TABLE events (
id INTEGER PRIMARY KEY,
app_id INTEGER REFERENCES applications(id),
happened_at DATE NOT NULL,
kind TEXT NOT NULL, -- 'applied', 'followed_up', 'screen', ...
notes TEXT
);
Three fields deserve a closer look because they're the ones spreadsheets never have.
posted_at matters because freshness matters. An application submitted the day a role goes live competes with dozens of candidates. The same application two weeks later competes with hundreds, many already in the pipeline. Track the gap between posted_at and applied_at and you'll see it in your own response rates.
stack_match is your honest estimate, 0 to 100, of how much of the required stack you cover. Score it when you source the role, before you apply. It becomes your best predictor, as you'll see below.
resume_version should point to the exact PDF you submitted. PDF specifically, because it locks your formatting and it's what you want a hiring manager opening. Name the files something like resume-backend-acme-2025-06.pdf so the tracker entry and the artifact can't drift apart.
Three numbers that change how you apply
The tracker earns its keep the first time you query it. Start with conversion by source:
SELECT source,
COUNT(*) AS applied,
SUM(stage IN ('screen','technical','onsite','offer')) AS screens,
ROUND(100.0 * SUM(stage IN ('screen','technical','onsite','offer'))
/ COUNT(*), 1) AS screen_rate
FROM applications
WHERE stage != 'sourced'
GROUP BY source
ORDER BY screen_rate DESC;
When a junior runs this for the first time, the usual discovery is that one channel, often referrals or direct applications to smaller companies, converts several times better than the job boards eating 90% of their hours. That single query justifies the whole system.
Second, screen rate by stack_match bucket. If roles where you match 80%+ of the stack convert at triple the rate of roles below 50%, and for most juniors they do, then every hour spent on sub-50 applications is an hour stolen from outreach on the good ones. The tracker turns a vague feeling of "nothing's working" into a specific instruction: raise your floor.
Third, stage-to-stage conversion, which tells you where to spend improvement effort. Lots of applications but no screens is a resume problem. Screens that never become technicals is a story problem, so drill your "walk me through your background" answer. Technicals that never become onsites means practice under time pressure. Without stage data you're guessing at which of these is broken, and juniors reliably guess wrong, grinding LeetCode when the actual leak is upstream at the resume.
The resume leak is worth a specific word, because it interacts with the freshness point. The fix is a resume tailored to each posting, submitted while the posting is days old rather than weeks. Doing that by hand at 150-application volume is brutal, which is the problem I started a company around. I build Roleframe, so I'm biased, but this workflow is what it does: track the jobs you're applying to, paste a posting, and get a resume tailored to it in seconds, with the exported PDF recorded against the application. If you'd rather stay in SQLite and tailor by hand, everything else in this article still stands.
Follow-up is where the compounding happens
Sales reps know most deals close on the follow-up, and most candidates never send one. That asymmetry is free advantage for anyone willing to be politely persistent.
A cadence that has served the engineers I've watched run disciplined searches:
- Day 0: apply, then find one relevant human at the company (recruiter, engineering manager, someone on the team) and send a two-sentence note saying you applied and why the role fits.
- Day 7: if silence, one short follow-up. New information helps: a relevant project you shipped, a specific line from the posting you're a match for.
- Day 14: one final nudge.
- Day 21: mark it ghosted and move on without guilt.
The next_action and next_action_at fields exist so this runs without willpower. Each morning, query for actions due today:
SELECT company, role, next_action
FROM applications
WHERE next_action_at <= date('now')
AND stage NOT IN ('rejected','ghosted','offer')
ORDER BY next_action_at;
That query is your job-search standup. Ten minutes, every day, and nothing falls through the cracks. The candidate who follows up on day 7 isn't more qualified than the one who doesn't. They're just the one the recruiter remembers when the shortlist gets made.
Set it up tonight
The junior market isn't going back to 2019. The volume is the volume, and the engineers getting through aren't the ones sending the most applications. They're the ones running the tightest process: fresh postings, tailored PDFs, tracked stages, disciplined follow-up, and a weekly look at their own conversion data to see what to fix next.
All of that starts with the tracker. Tonight, create the table, or the Notion board if that's more your speed. Backfill your last ten applications from your email, including the ones that went nowhere, because the failures are where the signal is. Then run the source query in two weeks and let your own data tell you where your next 40 hours should go.
You can't control how many people apply to the role you want. You can control being early, being tailored, and being the applicant who followed up. That turns out to be most of the fight.

Top comments (0)