Blog

  • The People and Problems Behind Klasstack

    The People and Problems Behind Klasstack

    Hey guys, I’m Omelihunna, and if you’d told me a few years ago that I’d end up building a school management software with a couple of my “colleagues turned friends” because of a comment my dad made in passing and years of watching my mom drown in heaps of paper every exam season, I probably would have looked at you with skepticism and gone back to whatever was eating my life at the time, which I lowkey believe to be CODM. 

    This whole thing started as a passion project, though I didn’t call it that at the time. If you’re like me that grew up with African parents, you know the rule that anything outside school counts as a distraction, at best a side hobby you’re supposed to grow out of. So in a way, building something for my mom became my excuse to somehow legitimize the fact that I had begun to have a career outside of the four walls of Uni. 

    Around the same time, my father had been watching me work myself to the bone at one of the many startups I was grinding through. He mentioned, almost in passing, that I should try building something of my own. It wasn’t a big speech or anything dramatic. He said it and moved on.

    But it sat with me for a few days, and eventually I reached out to Innovin, one of the smartest Engineers I’ve had the pleasure of living and working alongside; if I do say so myself. We’d been roommates from 200lv up until 400lv, so by the time I called him about “Klasstack”, he already knew how my brain worked and I knew how his did too. He was in almost immediately, and the two of us became the first co-founders. 

    Klasstack started from a single Google doc

    When I tell you we began with a single Google doc, it almost sounds unbelievable. For about two weeks we dumped every idea we had into it, because we knew the people (School owners, Teachers, Parents) we wanted to make life easy for, needed to see tangible value in whatever we were building before they’d bother paying any modicum of attention. So we shadowed about 5 different schools over the course of 3 weeks. Got to understand how things worked day to day, and kept running into the same handful of problems everywhere we looked. 

    Parents had no reliable way of knowing their kids had been checked in; Result compilation was messy with human error; School fees came with its own chaos of missing receipts and miscommunication that made reconciliation a headache; And child pickup relied almost entirely on School admins recognizing a parent’s face, which is a fairly shaky system when you think about it for more than a minute.

    We spent roughly 4 months building out the MVP. Somewhere in that process, Innovin and I both landed on the same realization, which is that great products get built all the time, but it takes an equally great team to make sure people find out how good the product is. 

    The other half of the Klasstack team

    So we brought in David, as our third co-founder, forever patient and always ready to be on the ground. He took on operations, which meant he became the one dealing directly with our founding schools, sitting through the same conversations more than once when a principal needed convincing or a teacher needed to see a feature work before trusting it. He was willing to visit as many times as it took to get things right, driving out on short notice, waiting around admin offices for someone with the right authority to be free, going back a second or third time when the first visit raised more questions than it answered.

    Then came our fourth co-founder, who for now would prefer to stay anonymous. She joined at a time when every day felt like there was something new to fix or figure out. Somehow, she loved it from the start. One of the first questions she asked me was whether I was hungry. I remember being confused enough that I just went huh, huh a couple of times before she explained what she meant. Hunger, she said, has a way of pushing people either to give up too soon or to push harder than they should. 

    Building something like Klasstack meant we’d need to know how to sit in that tension, how to push hard without losing the sense of when something wasn’t working, and how to be willing to go back and rebuild if it failed, and rebuild again if it failed after that. That conversation stuck with me longer than I expected it to, and it was really all the confirmation we needed that she was the right person to bring on.

    And that, more or less, is how the four of us ended up here — building Klasstack together to make schools operate with more ease and still figuring out most of it as we go. 

    PS: All em dashes and semi-colons are sponsored by our marketing team.

     

  • Reliability is a feature: how we think about engineering at Klasstack

    Why building school software that holds up on its worst day matters more than building software that only works in a demo.


    Most software is built and tested in comfortable conditions. Fast internet, steady power, a quiet room, one person clicking through at their own pace. Schools do not run in those conditions. A school runs during a downpour that takes the network with it, during a power cut in the middle of the afternoon, with a hundred things happening at once and a queue of parents at the desk.

    So the first thing we decided as an engineering team at Klasstack was simple to say and hard to live up to: reliability is not a nice-to-have on top of the features. It is the product. A tool a school cannot trust on its worst day is not really a tool at all. Here is how that belief shapes the way we build.

    We build for the environment our users are in, not the one we develop in

    It is easy to build something that works on a developer’s laptop and forget that the laptop has fast internet and a full battery. Our users do not. So we design the important flows to survive the moments that matter, and to catch up quietly when conditions improve. The goal is that a busy administrator never has to think about the plumbing. They do their work, and the system holds up around them.

    Simplicity beats cleverness

    Every extra moving part is another thing that can break when no one is around to fix it. We would rather ship something plain that works every single time than something clever that works beautifully in a demo and fails when it matters. When we review our own work, the most useful question we ask is not “is this impressive,” it is “what happens when this goes wrong, and who is there to notice.” The best answer is usually the simplest design.

    Your school’s data is yours, and we treat it that way

    A school platform holds sensitive information: children’s records, family contacts, fees, results. We treat that as a responsibility, not just data. Each school’s information is kept separate from every other school’s. Access is granted on a need-to-use basis, so a member of staff sees what their role requires and no more. And your data is yours. We do not sell it, and we do not treat it as a product to be traded. Trust, once lost, does not come back, so we would rather be careful than sorry.

    Software is only half the job

    We have learned that the best-built feature still fails a school if the school is left to figure it out alone. So we do not think our job ends when the code ships. It ends when a school is confident using it. That belief pulls engineering and support closer together than they usually sit. We build things to be understood, not just to be technically correct, because a feature no one can use with confidence may as well not exist.

    What this means for your school

    You should not have to know or care how any of this works. That is rather the point. When you run Klasstack, the promise is quiet and consistent: it holds up when the day is hard, it keeps your information safe, it stays simple enough to trust, and there are real people behind it when you need them.

    That is the kind of software we want to build, and the kind we would want running our own school.

  • Parent–School Communication That Actually Works

    Parent–School Communication That Actually Works

    Most schools communicate with parents through a tangle of WhatsApp broadcast groups, paper notes in school bags, and the occasional SMS. It feels like communication, but messages get buried, notes never make it home, and parents only really engage when something’s gone wrong. Here’s how to build communication that actually reaches families and builds trust.

    Why WhatsApp groups aren’t enough

    Broadcast groups have real limits as a school’s primary channel:

    • Messages get buried under dozens of others within minutes.
    • You can’t tell who saw what.
    • There’s no structure — fees, results and announcements all blur together.
    • It mixes school business with social chatter, which parents find tiring.

    They’re fine for casual updates, but they shouldn’t carry your important communication.

    Give parents one trusted place

    The fix is to give every parent a single, reliable place for everything about their child — results, attendance, fees and official announcements — instead of scattered channels. That’s the core of good parent communication tools: when parents know where to look, messages stop getting lost.

    Communicate proactively, not just when there’s a problem

    The schools parents trust most are the ones that share good news and routine updates, not only fees and problems. A few habits make a big difference:

    • Regular announcements about events, achievements and reminders.
    • Real-time visibility into results and attendance, so parents aren’t waiting for the end of term to know how their child is doing. See exactly what parents get.
    • A consistent voice — official updates that look and feel like they’re from the school.

    Make fee communication painless

    Fees are where communication most often turns awkward. Automating it removes the friction:

    • Polite, automatic fee reminders before and after due dates.
    • Clear statements parents can see any time.
    • Instant receipts, so there’s never a dispute about whether a payment landed.

    When fee communication is automatic and consistent, it stops being a source of tension.

    Reach every family, not just the active ones

    The parents who most need an update are often the ones least active in a WhatsApp group. A system that delivers to every parent — and lets you target the whole school, a class or an individual — means no family is left out of the loop because they missed a message in a crowded thread.

    Keep it human

    Tools handle the routine, but relationships are built in the exceptions. Use the time saved by automating announcements and reminders to have real conversations with the families who need them. The best communication strategy is efficient systems plus genuine care.

    Frequently asked questions

    Should we stop using WhatsApp entirely? Not necessarily — but it shouldn’t be your primary channel for important information. Use a structured system for results, fees and official announcements, where messages won’t get buried.

    How do I make sure every parent sees an update? Use a platform that delivers to every parent’s account and lets you target the whole school, a class or an individual, rather than relying on who happens to be active in a group.

    How can fee reminders avoid being awkward? Automate them. Polite, consistent reminders from the system — before and after due dates — take the personal discomfort out of chasing payments.


    Bring your parent communication into one calm place. Start free with Klasstack.

  • The Two-Year-Old Decision Quietly Eating Your Memory

    I recently came across a small commit switching one query from offset to cursor pagination. A few lines changed. Ordinary Tuesday stuff.

    But it sent me right down memory lane, because there is a special kind of wahala that never shows up in code review, never fails a test, and never pages anybody at 3am on launch day. It waits. It sits quietly inside a batch job you wrote when the table had 40,000 rows, behaving itself perfectly, until one random Tuesday three years later the same job starts chopping memory like it skipped breakfast. And you’re staring at an out-of-memory crash asking the ancient question: what changed?

    Nothing changed. That’s the whole trick. You didn’t change anything. The table did.

    The entire answer in one line

    If you carry only one thing from this post, carry this: it depends on who is doing the paging.

    If a human is clicking through pages in a UI, page 3, then page 8, then back to page 2, that is offset work. Humans jump around, and offset lets them.

    If a machine is grinding through the whole table in the background, a batch job, a sync, a nightly export, anything that starts where it stopped and keeps marching, that is cursor work. Machines don’t jump around. They march forward and want to resume exactly where they left off.

    Get that split right and most of your pagination pain disappears. Now let me show you why it works that way, and why the machine case is the one that betrays you quietly.

    The bet you forgot you placed

    When you write a paginated sweep over a table, you place a quiet little bet on how big that table will get. The cruel part is that the bet is invisible. Offset pagination and cursor pagination look almost identical in the code. Same loop, same batch size, same upsert. One of them scales gracefully forever and the other slowly turns into a tar pit, and from across the room you cannot tell them apart.

    So the offset-based feeder you shipped two years ago was not wrong. On a small table it was genuinely fine. Cheaper to write, easier to reason about, worked on the first try. The PR merged, everybody moved on, and the decision fell out of everyone’s head. Which, to be fair, is exactly what is supposed to happen to decisions that work.

    Except the table kept growing, small small, in the background. And offset has one nasty property: the deeper you page, the more work the database does per page. Not the same work. More. Every single run. So the cost never stayed flat. It crept upward alongside your row count until one day it crossed the invisible line marked “available memory” and the whole thing fell over.

    The job crashing today is not today’s job. It is a two-year-old decision finally presenting its bill. With interest.

    And notice the shape of the casualty: a batch job, a machine sweeping the entire table. The exact case that should have been cursor from day one. Let’s break both down properly.

    Offset pagination, explained like we’re gisting

    Offset is “skip plenty, then grab some.” You tell the database: skip the first 40,000 rows, give me the next 10,000.

    The problem is the word skip. Databases cannot teleport to row 40,001. There is no shortcut, no bookmark. To skip 40,000 rows, the database physically walks past all 40,000 of them, looks at each one, and throws it away, just to reach the ones you actually asked for.

    Picture reading a novel by starting from page one every single time. Flip flip flip to where you stopped, read one page, close the book. Next session? Back to page one. By the time you finish the book, you’ve flipped through the entire thing hundreds of times. That is offset doing a full sweep. Page 1 is instant. Page 900 makes the database count to nine million before it hands you a single row.

    Where it shines: a UI with an actual human inside it. When someone is browsing results and wants page 1, then page 5, then back to page 2, offset is exactly right. “Page 5, please” is easy to write, easy to hold in your head, and jumping straight to any page is instant. This is offset’s home turf, and cursor would only be a nuisance here.

    What’s good about it:

    • Dead simple. Your junior dev understands it in one glance.
    • Jumps anywhere instantly, perfect for a UI where someone clicks straight to page 47.
    • Perfectly fine on small or slow-growing tables. Genuinely. Let nobody shame you.

    What bites you:

    • Cost grows with depth. Deep pages get expensive, and a full sweep gets quadratically expensive as the table grows. That is the entire tar-pit-three-years-later story.
    • It is a position, not an anchor. If a row ahead of you gets deleted mid-sweep, everything shifts down by one and you silently skip a row. An insert, and you process one twice. Offset counts positions, and positions move.
    • The pain is invisible until it isn’t. Small table, no symptoms. Big table, sudden fire. Nothing in between to warn you.

    Those last two points are exactly why offset is a terrible fit for a long-running batch sweep: the job pages deep (it visits every page) and it runs while data changes underneath it. Both of offset’s weaknesses, landing at the same time. Double wahala.

    Cursor pagination, explained the same way

    Cursor (also called keyset, also called “seek”) throws away the page number entirely. Instead of “skip 40,000,” it remembers the last row it saw and says: give me everything after this specific row.

    You keep an actual bookmark. “Last time I stopped at the row with timestamp X and id Y. Give me what comes after that.” If there is an index on those columns, the database seeks straight to your bookmark and reads forward. No skipping. No counting to nine million. It opens the book exactly where you left it.

    Every session costs the same, whether you’re on page 2 or page 900. That is the superpower.

    Where it shines: batch jobs and anything that resumes. A feeder syncing a table into a search index, a nightly export, a migration, a job that got killed halfway and needs to continue from where it died. Because the bookmark is a real value from the data, you can write it down (stash it in Redis, say) and tomorrow’s run picks up exactly where today’s stopped. This is cursor’s whole reason for existing, and it is precisely what a batch job wants.

    What’s good about it:

    • Flat cost. Page 900 costs the same as page 2. A full sweep scales linearly, so the tar pit never forms.
    • Stable under changes. The bookmark points at real values from the data, not a row count. Rows can appear and vanish elsewhere and your bookmark still means exactly what it meant. No skips, no doubles.
    • Naturally resumable. “I was on page 900” becomes meaningless the moment data moves. “I stopped after row X” stays true forever.

    What bites you:

    • More fiddly to write. You’re threading “the last row I saw” through the loop instead of multiplying a page number.
    • No jumping to page 47. Cursors only move forward from where you are, so random access is not really a thing. Which is exactly why it’s wrong for a browse-y UI and right for a march-forward batch job.
    • The bookmark must be unique, or it lies to you. This is the sharp edge, so shine your eye here. If you bookmark on a timestamp alone and 5,000 rows share that timestamp, “everything after this timestamp” splits that group down the middle and you skip or double the rest. The fix is a compound bookmark: the timestamp plus a tiebreaker like the primary key. Now every row has a strict, unambiguous order, and “after this point” always means one exact spot. And your ORDER BY and your “after this” filter must name the same columns, or the whole scheme quietly falls apart.
    • It leans on an index. The flat cost is real only if there’s an index on the columns you’re seeking by. No index, and your fancy cursor quietly rots back into offset’s cost. The index is doing the heavy lifting. Respect it.

    So what do we actually do?

    Not “cursor everything.” That is just swapping one thoughtless default for another. The rule from the top of this post is the real answer:

    • A human moving through pages in a UI? Offset. Simple, correct, instant random access.
    • A batch job, sync, or anything that resumes? Cursor. Flat cost, stable under writes, resumable. Offset here is the thing that OOMs in three years.
    • Not sure how big the table gets? Cursor, and thank yourself later. It is the option that fails gracefully instead of falling off a cliff.

    And the quieter lesson underneath all of it: the assumption is the dangerous part, not the code. When you write a paginated sweep, you are betting on a table size and a usage pattern. So say the bet out loud. Drop one comment:

    // offset is fine here: human-facing UI, table capped around 50k
    

    That one sentence is a tripwire. It turns a silent, forgotten assumption into something the next person, probably future-you, bleary and confused in front of an OOM log at 2am, can actually find and go: “Ah. The bet. The bet broke.”

    The bug that gets you is never the one you’re watching on launch day. It is the reasonable little decision you made when everything was small, that you completely forgot, that was quietly compounding the whole time. Reaching for offset on a batch job is a world-class way to write one of those.

    So write the comment. Leave the tripwire. Give three-years-from-now-you a fighting chance.

    They’re going to be so tired.

  • The Term-Start Checklist Every Nigerian School Administrator Needs

    The Term-Start Checklist Every Nigerian School Administrator Needs

    The first two weeks of term set the tone for the whole session. Get resumption organised and everything runs smoother; let it slip and you spend the term firefighting. Use this checklist to start every term in control. Much of it can run from one platform instead of scattered files.

    2–3 weeks before resumption

    Confirm enrolment

    • Finalise the list of returning students and new admissions.
    • Move accepted applicants into full student records (this is effortless if your admissions and enrolment flow carries applicants straight into records).
    • Identify any students who haven’t confirmed return and follow up.

    Set up classes and arms

    • Confirm class structure and arms for the new session.
    • Assign students to classes.
    • Promote the previous term’s students where appropriate.

    Prepare the fee structure

    • Confirm tuition and levies for the term.
    • Apply scholarships, sibling discounts and any approved adjustments.
    • Publish the fees so parents can pay online before resumption.

    1 week before resumption

    Staff and timetables

    • Confirm teaching assignments and any new hires.
    • Build the timetable and share it with teachers and students.
    • Make sure every staff member has the right system access for their role.

    Communication

    • Send a resumption announcement to all parents: date, fees, requirements.
    • Confirm contact details are up to date so messages actually reach families.

    Open fee collection early

    • Encourage parents to pay before day one. Early online payment smooths the first week enormously and improves your cash position.

    First week of term

    Attendance from day one

    • Have teachers mark attendance from the very first day so you spot non-resumers early.

    Track fees actively

    • Watch the arrears view and send polite reminders to parents who haven’t paid.
    • Confirm part-payment and instalment arrangements are recorded.

    Settle academics

    • Confirm subjects, scheme of work and any assessment dates.
    • Make sure teachers can enter scores when the time comes.

    Throughout the term

    • Keep parents informed with regular announcements, not just problems.
    • Monitor attendance trends and follow up on patterns early.
    • Keep fee collection moving rather than leaving it to term-end.
    • Prepare for results well before the final week so report cards aren’t a scramble.

    Why a single system makes this easier

    The reason term-start feels chaotic is usually fragmentation — enrolment in one file, fees in another, timetables on paper, communication in WhatsApp. When admissions, fees, classes, attendance and communication share one platform, each step on this checklist feeds the next automatically. That’s exactly what school owners and admins get from a connected system.

    Frequently asked questions

    When should I open fee collection for a new term? As early as possible — ideally 1–2 weeks before resumption. Online payment lets parents pay ahead and improves your first-week cash position.

    How do I avoid the result-week scramble? Make sure teachers can enter scores throughout the term and that grading is configured early, so report cards are generated, not assembled by hand at the last minute.

    What’s the most common term-start mistake? Fragmented tools. When enrolment, fees and communication live in separate places, work gets duplicated and things fall through the cracks.


    Start your next term in control. Get started free with Klasstack.