Blog/Case Studies

Building PreMeder: From Personal Frustration to 12,000 Users

The story of building a pre-med platform from scratch and growing it to thousands of active users.

Introduction

I built PreMeder because the existing tools for tracking a pre-med journey were embarrassingly bad. Spreadsheets with 40 tabs. Sticky notes on monitors. GroupMe threads where someone asks for the third time which schools accept AP credit. The entire pre-health application process, AMCAS, AACOMAS, TMDSAS, is a logistics problem, and nobody had built a proper tool to solve it.

PreMeder started as a personal project to track my own clinical hours and school list. It now has over 12,000 active users. This is the story of how it got there, what I built, and what I learned about shipping a product for a niche community that desperately needed one.

A team of medical professionals collaborating in a clinical environment
The pre-medical community is driven by collaboration and shared experience. PreMeder was built to give that community the organizational tools it deserved.Photo on Unsplash

The Problem

If you have never applied to medical school, the scope of the tracking problem is hard to appreciate. A typical applicant manages the following simultaneously:

1
Clinical and volunteer hours. Medical schools want to see sustained commitment. You need to log every shift, supervisor, reflection, and running total across categories: clinical volunteering, non-clinical volunteering, shadowing, research, paid clinical work. Most applicants track this in a spreadsheet that grows unwieldy by month three.
2
School list management. The average applicant applies to 20-30 schools. Each school has different secondary essay prompts, deadlines, interview formats, mission statements, and admissions statistics. You need to track where you are in the pipeline for each one: primary submitted, secondary received, secondary completed, interview invited, accepted, waitlisted, or rejected.
3
Timeline coordination. AMCAS opens in May, secondaries arrive June through August, interviews run September through March, and decisions come April through June. Missing a secondary deadline by a week can tank your chances at a school. The entire cycle demands a tracking system, and most applicants cobble one together from Google Sheets and willpower.
The insight that started everything

Pre-meds are some of the most organized people I know, and they were still drowning in spreadsheets. The problem was not discipline. It was the absence of a tool designed for the specific workflow.

Technical Stack

I chose the stack based on two constraints: I was the only developer, and I needed to ship fast. Every technology choice was filtered through the question: does this let me move faster without creating debt I cannot pay back later?

The Stack

LayerTechnologyWhy
FrameworkNext.js (App Router)Server components, API routes, and static generation in one framework
DatabasePostgreSQL + PrismaRelational data with type-safe queries and zero migration headaches
AuthNextAuth.jsGoogle OAuth for frictionless sign-up, session management handled
HostingVercel + SupabaseEdge deployment, managed Postgres, no DevOps overhead
StylingTailwind CSSRapid iteration on UI without context-switching to CSS files

The decision to use PostgreSQL over a NoSQL option was critical. Application tracking is inherently relational. A school has many secondaries. A user has many schools. An activity has many hours entries. Trying to model this in a document store would have created join nightmares within the first month.

Prisma gave me type-safe database queries that caught schema mismatches at compile time. When you are the only developer and there is no code review, the compiler is your code reviewer.

Core Features

PreMeder has three pillars. Each one addresses a specific pain point that I experienced personally and validated with dozens of conversations in pre-med communities.

Application Tracker

The tracker models the full application lifecycle as a state machine. Each school-application pair moves through defined states: not started, primary submitted, secondary received, secondary submitted, under review, interview invited, interview completed, and finally one of accepted, waitlisted, or rejected. Transitions are validated server-side to prevent impossible state jumps.

typescript
// Simplified state machine for application status
const VALID_TRANSITIONS: Record<AppStatus, AppStatus[]> = {
  NOT_STARTED:        ['PRIMARY_SUBMITTED'],
  PRIMARY_SUBMITTED:  ['SECONDARY_RECEIVED'],
  SECONDARY_RECEIVED: ['SECONDARY_SUBMITTED'],
  SECONDARY_SUBMITTED:['UNDER_REVIEW'],
  UNDER_REVIEW:       ['INTERVIEW_INVITED', 'WAITLISTED', 'REJECTED'],
  INTERVIEW_INVITED:  ['INTERVIEW_COMPLETED'],
  INTERVIEW_COMPLETED:['ACCEPTED', 'WAITLISTED', 'REJECTED'],
  WAITLISTED:         ['ACCEPTED', 'REJECTED'],
  ACCEPTED:           [],
  REJECTED:           [],
}

Hours Logger

The hours logger tracks activities across AMCAS categories with running totals, supervisor information, and per-entry reflections. The hard part was not logging hours. The hard part was making it fast enough that people would actually use it instead of defaulting back to their spreadsheet. Every interaction, adding an entry, editing a total, switching categories, needed to feel instant.

I implemented optimistic updates on the client side. When a user logs hours, the UI updates immediately while the write propagates to the database asynchronously. If the write fails, the UI rolls back. This pattern cut perceived latency from 400ms to under 50ms.

School List Builder

The school list builder aggregates admissions data, average MCAT, GPA ranges, mission statements, and secondary prompts, and lets users build a balanced list of reach, target, and safety schools. The data layer pulls from a curated dataset that I maintain manually, cross-referencing MSAR data with publicly available admissions statistics.

Growing to 12,000 Users

I did not run ads. PreMeder grew entirely through organic distribution in pre-med communities. The growth curve had three phases.

1
Phase 1: Reddit and Discord (0 to 500 users). I posted about PreMeder on r/premed and in pre-med Discord servers. The initial reception was skeptical, as it should have been. Pre-meds had seen tools come and go. What converted the first users was the hours logger. It solved an immediate, daily pain point. Once someone logged their first week of clinical hours, they were hooked.
2
Phase 2: Word of mouth (500 to 4,000 users). The application cycle is social. Pre-meds talk to each other constantly about where they are in the process. When one person in a study group uses a tool that makes tracking effortless, the rest of the group asks about it. This organic loop drove the majority of growth. I did not engineer it. I just built something people wanted to talk about.
3
Phase 3: Community trust (4,000 to 12,000 users). Once PreMeder appeared in recommendation threads unprompted, growth became self-sustaining. Pre-med advisors at universities started recommending it. Student organizations included it in their resource guides. The product had crossed the threshold from tool to community infrastructure.
Growth lesson

You do not need a marketing strategy for a niche product. You need a product so good that the niche markets it for you. Every hour I spent on product quality returned more users than any hour I could have spent on promotion.

A collaborative team working together on building community software
Building PreMeder meant translating the frustrations of the pre-med application process into software that 12,000 students now rely on daily.Photo on Unsplash

Technical Challenges

Scaling from a personal tool to 12,000 users surfaced problems I had not anticipated.

Real-time sync across devices. Many users log hours on their phone during a shift and review their application tracker on a laptop later. The data needed to be consistent across devices within seconds. I implemented this with a combination of SWR for stale-while-revalidate caching and WebSocket-based invalidation for critical state changes like application status updates.

Mobile responsiveness under load. The application tracker displays a dense grid of schools and statuses. On a phone screen, this became unusable. I rebuilt the mobile layout as a card-based interface with swipe gestures for status transitions, which actually turned out to be faster than the desktop grid for quick updates.

Data integrity during the cycle. During peak secondary season (July-August), users are making dozens of updates per day. Race conditions between optimistic updates and server-side validation could produce inconsistent states. I added idempotency keys to every mutation and implemented server-side conflict resolution that always favored the most recent user intent.

typescript
// Idempotent mutation with conflict resolution
async function updateApplicationStatus(
  userId: string,
  schoolId: string,
  newStatus: AppStatus,
  idempotencyKey: string
) {
  return await prisma.$transaction(async (tx) => {
    const existing = await tx.mutation.findUnique({
      where: { idempotencyKey }
    });
    if (existing) return existing.result; // Already processed

    const app = await tx.application.findUnique({
      where: { userId_schoolId: { userId, schoolId } }
    });

    if (!VALID_TRANSITIONS[app.status].includes(newStatus)) {
      throw new InvalidTransitionError(app.status, newStatus);
    }

    return await tx.application.update({
      where: { id: app.id },
      data: { status: newStatus },
    });
  });
}

What I Learned

Building PreMeder taught me things that no computer science course covers.

1
Niche products win on empathy. I am a pre-med. I understood the pain because I lived it. Every feature decision was informed by my own experience. If you are building for a community you belong to, you have an advantage that no amount of user research can replicate.
2
Ship the smallest useful thing first. The first version of PreMeder was just the hours logger. No school list builder. No application tracker. Just a clean way to log clinical hours. That single feature was enough to get the first 500 users, and their feedback shaped everything that followed.
3
Trust compounds. Pre-meds are entrusting PreMeder with data that affects their career. The application cycle is stressful, and a data loss incident would be unforgivable. I invested heavily in backups, data export, and transparent communication about uptime. That trust is the reason the product grew, and it is the thing I guard most carefully.

Conclusion

PreMeder exists because I was frustrated, and I could code. That is the entire origin story. The technical decisions were important, but the product instinct came from being the user. I did not need to interview customers to understand the problem. I was the customer.

12,000 users later, the most meaningful metric is not the number. It is the messages I get from applicants who say PreMeder helped them stay organized during the most stressful year of their lives. That is worth more than any technical achievement in the stack.

For builders in niche communities

If you belong to a community with an unsolved problem, build the solution. You already have the domain expertise. You already have the distribution channel. The only thing between you and a product people love is the willingness to start.

Stay in the loop

Follow along as I explore the intersection of medicine, AI, and engineering.

Just honest writing, straight from me. Unsubscribe anytime.