Avoid Mini-Frameworks
Key topics
The debate around "mini-frameworks" has sparked a lively discussion, with many commenters weighing in on the author's assertion that these lightweight abstractions can often do more harm than good. While some, like hu3 and aefalcon83, agree that premature abstraction and poor boundary setting can lead to unnecessary complexity, others, such as gaigalas and anon5739483, point out that the problem isn't unique to mini-frameworks and that context plays a significant role in determining their usefulness. As the conversation unfolds, it becomes clear that the distinction between libraries and frameworks is blurry, with React being a prime example of a "library" that has evolved into a full-fledged ecosystem, as noted by iTokio and davnicwil. The discussion highlights the challenges of defining these terms and the need for a nuanced understanding of when to adopt new abstractions.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
N/A
Peak period
86
0-12h
Avg / period
19.5
Based on 117 loaded comments
Key moments
- 01Story posted
Dec 24, 2025 at 7:04 AM EST
10 days ago
Step 01 - 02First comment
Dec 24, 2025 at 7:04 AM EST
0s after posting
Step 02 - 03Peak activity
86 comments in 0-12h
Hottest window of the conversation
Step 03 - 04Latest activity
Dec 31, 2025 at 12:16 AM EST
3d ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
I can be found here: https://x.com/laike9m https://mastodon.social/@laike9m
That is also true for "macro" frameworks.
> Wraps around the company/org-shared tech stack or framework
That is often also true for "macro" frameworks.
> Creators claim that the framework "magically" solves many problems, and push more people to use it
That is often also true for "macro" frameworks.
---
It is not clear from the reader's perspective what actually characterizes a "micro" framework. It's also not clear why the size is the issue here, when all complaints seems to be about design or quality.
Is googletest a micro or macro framework? Give us some clarifying examples. Actual things people can look for, not internal unknowable projects. There must be some exceptions too (silver bullet rules don't exist), mention them.
Also, rethink the title. Maybe "makeshift frameworks" is better terminology, as it more accurately reflects the problem that is described in the content.
The "micro framework" phase happens when that "macro" framework fails to deliver something. It happens way less often than a team picking a big estabilished tool.
However, the sizes never mattered. That is likely what causes the confusion in the first place ("it's large so it must have lots of things I want", "it's small so it must be easy to understand").
The real red herring is focusing on the size (or LOC, or any vague metric) instead of other more relevant architectural properties.
However, for a beginner, specially if said beginner never worked in a larger company with resources to produce an internal framework, they might think you're referring to Flask or something like that (btw Flask-style microframework use can go very wrong but it's another completely different issue).
That's why I'm being nitpicky. The people who'll get the post are likely already experienced enough to evaluate those frameworks themselves.
This isn't what is normally understood in software engineering by those terms.
A library is something you call.
A framework is some kind of application scaffolding that normally calls you.
You can use more than one library. You normally only have one framework in-process.
I found the blog post a little hard to parse. Is it an argument against wrapping frameworks, or wrapping libraries?
I agree that wrapping frameworks is fraught with danger. I can't quite agree for wrapping libraries. Wrapping libraries makes a lot of sense if you're only using a tiny fraction of the library functionality, the breadth of the wrapper's API is much smaller than the library's API, wrapping it enables you to substitute it (whether for a smaller / faster / whatever dependency in the future, or for testing, etc.), and so on.
For example I mostly agree with your calls/called definition but you also get self-described libraries like React giving you defined structure and hooks that call your code.
React's Wikipedia page says "React ... is a free and open-source front-end JavaScript library", and has no mention of Framework.
Why die on a hill that it "is" something it says it isn't?
[] https://react.dev/
[] https://en.wikipedia.org/wiki/React_(software)
Because I think they're wrong about that.
In another comment I used the example of rails as a kind of canonical 'framework' that can potentially do everything for you full stack, and django is in the same category, juxtaposed against something like React that cannot.
To that, I think your last paragraph is the one I agree with most closely. It's true, but only for the view part of the app, right? I think that's where I get stuck on stretching to calling it a framework.
I guess I can see it if you're defining your view/client as a separate logical entity from the rest of the stack. Which is totally reasonable. But I guess just not how I think about it.
There's plenty of guru who say that they are the reincarnation of Jesus and/or Buddha, doesn't mean that we take their word for it.
In the same vein, North Korea is officially the "Democratic People's Republic of Korea", even though it's obviously not a democracy.
The later stuff adds other ways of doing the same thing but a library it remains.
That's as self described by the React team, and I think the consensus more broadly.
Library is something that can be pulled off project and replaced with something else. There's no non-trivial project where replacing React with anything would be possible. Every React web app is built around React.
Id maybe concede that frameworks are a subset of libraries. You can use most frameworks in a library fashion, but the opposite is not true (you'd need a mini framework)
I think you can probably see that distinction already, but to spell it out React is described as a library precisely because it does just one thing - the view - and leaves it to you to figure out the entirety of the rest of the stack / structure of your app.
Framework, at least to me, but I also believe commonly, means something that lets you build a full application end to end using it.
You can't do that with React unless your app is just something that lives in the browser either in-memory or with some localstorage backing or something. If that's your app, then probably I'd agree React is your framework per se, but that's hardly ever the case.
By the way, back to my original point, I still do think these things are impossible to define and in lots of ways it doean't matter - if it's a framework for you, it's a framework - but I just had to defend my position since you described it as absurd :-)
It introduces JSX, which is technically speaking its own programming language independent of JavaScript.
It defines hooks like useState() and useContext() for state management, meaning it is not UI only, plus "function based" components that act as a pseudo DSL that is pretending to be functional JavaScript (which it isn't).
Most of the time you're expected to render the entire page body via react.
You couldn't get further away from the idea of a library.
Framework can be more or less modular, Angular or Ember choose to be 'battery included', while React choose to be more modular, which is simply choosing the other spectrum of the convenience-versus-flexibility tradeoff.
React ostensibly only care about rendering, but in a way that force you to structure your whole data flow and routing according to its rules (lifecycle events or the 'rules of hooks', avoiding mutating data structures); No matter what they say on the official website, that's 100% framework territory.
Lodash or Moment.js, those are actual bona fide libraries, and nobody ever asked whether to use Vue, Angular or Moment.js, or what version of moment-js-router they should use.
It is a programming pattern/class.
Example Node.js EventEmitter usage:
const EventEmitter = require('events');
emitter.on('data', handler);
emitter.emit('data', value);
-----------
You explicitly instantiate it. You explicitly register listeners. You explicitly emit events. It does nothing unless you call it. There's no lifecycle, no main loop, no required structure.
EventEmitter is not a framework because it does not define application structure. It doesn't own the program's control flow. It doesn't decide when your code runs (beyond callbacks you register). It does not enforce conventions or architecture.
People sometimes call it a framework incorrectly because of two sources of confusion:
1. Callback-based APIs feel like inversion of control. But this is partial IoC, not framework-level iOc.
2. It is often embedded inside frameworks. Examples: Express routes, React synthetic events, Electron internals.
The promise is to simplify and unify things but as noted, such efforts more often than not have the opposite effects.
Programmers HATE using other people's abstractions, which is why "mini frameworks" tend to tall apart after expanding to teams that don't have control over it. In my experience, this leads to new mini frameworks wrapping the first one, forever targeting a static version of the underlying MF, to allow for adding new appendages without going through a gatekeeper.
It would be much better if we get more humble people who get down to work to understand why and how existing code or framework works instead of trying to work around it or simply throwing all away and writing their own code.
Thera are of course some exceptions - but those are like pro athletes - no you are not the one, learn existing code instead of making excuses about some edge cases you ran into so you have to rewrite all from scratch.
I'm all for aggressive refactoring if it leads to something simpler.
There are caveats here too of course - forking everything and excessive NIH comes with their own costs and risks.
This is the real problem. Too often frameworks/libraries are geared towards making things magic instead of making things solid. Magic solutions are usually very one dimensional. e.g. The Magic only works for a really narrow use case, or at low load. I don’t think this is specifically a problem with “mini frameworks” but homegrown stuff exhibits this more, if only because magic solutions tend to die in the wild when the bug tracker is full of “this only works for trivial case; make it actually work”.
When frameworks/libraries advertise how easy they are to get started, there is often a lot of magic to make it trivial to start and they don’t scale to real projects without breaking through all the magic abstractions.
Ruby on Rails is probably a great counter example here though.
That said, I suspect that Ruby on Rails itself occupies kind of a special space where the magic is acceptable because people who write Ruby are used to having very very sharp tools and have learned to wield them carefully. Give that magic to a PHP or Java programmer and there is immediately gallons of blood on the floor.
(says former Rubyist who was put off by the RoR stuff because I'm apparently more of a Haskeller at heart.)
Of course, your hodgepodge ecosystem will eventually ends up a bit of a mess, but I'll take that over a flashy off-the-shelf framework that insists on handling everything itself.
I think this is the main problem.
I don't mind layers of abstraction when they work well and their components compose nicely. Like a well-designed programming language. These can actually be quite fun to work with.
Layers of abstraction where the boundaries between that layer and those around it are fuzzy to non-existent and where certain cases magically work and everything else is a janky mess because it was never designed to work are what give me headaches and want to throw my work laptop out the window on a regular basis.
After all, hindsight is 20/20 and at the end of the day a major part of our work is making (appropriate) abstractions. Picking good terminology is sometimes hard. I guess to point out that the message shouldn't be read as "all abstractions bad (stop trying)" but to be more conscious about them and to restrain from piling new "magic" on top of a tower of old apocrypha.
> A framework is some kind of application scaffolding that normally calls you.
There is no real distinction between these two.
https://en.wikipedia.org/wiki/Inversion_of_control
The best assumption to start with is that adapters are bad by default, because they are an unnecessary layer to maintain (and potentially a point of failure and bottleneck depending on what they are and do). Then, make the argument for the adapter as a guilty until proven innocent case.
If you can make a solid case for it, fine. There are many solid cases for adapters, e.g. drivers for a database or hardware.
Never write an adapter that you can handle more scalably, flexibly, and almost as easily by calling something directly.
Certainly you should not wrap a library “just because”. The benefit of doing so should be easy to articulate.
If I had to bring the point home I'd say that the author himself committed the very mistake he is warning against in that very sentence.
Frameworks define conventions and non-language features (language feature=data structures, callable functions, etc) that cannot be expected to be understood by simply reading the existing code and therefore need to be learned explicitly by reading the documentation of the framework. Frameworks are allowed to bend rules and expectations, because you're supposed to learn and be aware of them ahead of time.
This directly applies to the irresponsible use of the word "concept". The meaning of what he was trying to convey cannot be understood based on simply reading the sentence.
I think English is not OP's first language, framework here basically means wrappers.
Don't call us, we'll call you.
Leave the driving to us.
I think I broadly agree with this. In essence, libraries don't impose an application-level life cycle. Frameworks, generally, do.
The rest of the article, I don't know….
The most successful, long-running app I maintain has a mini-framework that allowed me to assemble what I need piecemeal rather than relying on any off-the-shelf framework that would have been obsoleted several times over in the seventeen-year lifespan of this code.
I guess about one in three things I do in it require me to dip into my framework code to look at it, but this is mostly to remember how it works! About one in five things have required me to make a small progressive change.
Twice in its lifetime a core component has been swapped out (mailer and database library).
And twice in its lifetime, because it is beginning to converge on a general web framework, I have considered porting the code out of it and into a general framework, which might make it easier to hand over. One day, I suspect, something will break compatibility in a way that makes that the sensible route, but the code works, fast, has a pretty obvious set of abstractions, and there are implicit examples of everything it can do in everything it already does.
Almost all articles like this start out with "here is a thing I claim is a generalised problem that you should not do, that is a well-meaning but false generalisation.
Underneath they are always: don't write bad code. If you do, learn from it.
If I'd followed the advice of this article when I started this project, I would by now have rewritten the entire thing more than once, for little gain.
imo it's better to just figure out the definition in the current context, than try to force your own definition unto others. You can't anyway.
This. A framework relies extensively on inversion of control. It provides the overall software architecture of an application, and developers just inject the components called by the app to customize some aspects.
A toolbelt of small utility-like composables are often easier to maintain and reason about. This results in added explicitness (i.e. less magic, fewer surprises).
Personal experience shows that the immediate efficiency gains of a framework often get diminished in the face of all the hacks people introduce later, just to work around the remaining 10% of cases that the framework did not anticipate or traded-off against.
Please note this is a comment based on personal experience and professional preference.
BOCTAOE.
The abstracted-away logic in a Laravel application can either be called magic or abstraction, but so can the optimizations of a database query planner.
I think often you still need to know the underlying mechanism, but it is still useful to get the innards out of the way.
The problem is that your code has to work within this abstraction and can only solve problems covered by the inventors of the abstraction.
Spring Boot and other similar frameworks come to mind; by forcing huge amounts of indirection you lose a lot of visibility of your call stack because the convenient "glue" code is now orchestrating everything at runtime, but that code isn't your and isn't easily inspected or fixed.
And I think twice before I use a framework. Frameworks enforce a certain way of programming which you can never be sure to match the problems you will have to solve in the future. Libraries don't do this - at least not to the extent of a framework. Libraries are composable building blocks.
Nevertheless, there may be applications where frameworks are beneficial (e.g. GNU Radio).
You have to define the terms.
It's not clear how your statement above isn't semantically equivalent to "prefer good over bad" or something otherwise nonsensical.
"Good magic decomposes into sane primitives" highlights an essential distinction: not all magic is bad (but it's not always clear at first which kind of magic is in play).
Start with a loose bag of functions. These are easy to compose in to larger pieces of functionality. And, this is key, easy to decompose when things change. Once this WET bag becomes a chore to change, the right abstraction might just show itself for DRY-ing out.
The worst is when three lines of completely standard code (immediately understandable to anybody inline) get „helpfully” lifted out into a utility function.
This article reminded me of two classic pieces of writing.
The first is 20+ years old now: Joel Spolsky's law of leaky abstractions:
https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-a...
One of the reasons these mini-frameworks lead to problems is that they leak. They don't cover every case which means you inevitably have to fully understand what they are doing for you in order to debug them or work around their limitations. Your cognitive load goes up!
The second is Will Larson's "Migrations: the sole scalable fix to tech debt."
https://lethain.com/migrations/
The OP complains that they've never seen a technology migration at Google that finished. Will advocates for migrations to be driven by a team that both coache other teams on the migration and then, crucially, finish the job themselves to make absolutely sure it gets done to 100% completion.
And it is very easy to start feel like you know you have a great abstraction when you don't. And unfortunately it's easy and fun to make abstractions, kinda like making babies. And has kind of similar weight to it too.
I just have to say.. stay safe out there.
Are you the Internet of Bugs gentleman?
For me, the only purpose of an abstraction is to reduce complexity, but often times I'm seeing it being used to reduce repetitiveness, which often times replaces well understood more verbose code with less understood less verbose and less flexible alternative. For me, as a team lead, easy to read code is far more important than subjectively perceived elegant abstraction that everyone then has to learn how to use, and potentially fight with.
In many cases I have noticed people jumping into abstracting away a complexity right away, often times ending up with a leaky or inflexible abstraction. To those people I say, do that painful thing at least 10 times, then think about abstracting it away, since then you probably have some level of understanding about the pain you're trying to alleviate and all the nuances that comes with that domain.
DynamoDB is admittedly very verbose, but it's almost always worth it to keep your CRUD operations written within the SDK rather than as an abstraction.
A framework calls you. You call a library.
A framework constrains the program. A library expands the program.
It’s easier to write a library that is future proofed because it just needs to satisfy its contract.
It’s harder to write a framework because it imposes a contract on everything that depends on it.
Just like it is hard to write tort law without a lot of jurisprudence to build out experience and test cases, it is hard to write a framework from only one use case.
No one likes lawyers because they block you from doing what you want. This is the problem with frameworks.
However the government likes laws because they block you from doing what you want. Same with engineering management that wants programmers to work in a consistent way.
> No one likes lawyers because they block you from doing what you want.
Or even doing what you need to do.
Certainly, to the extent that a mini-framework is composed of more constraints piled on top of an extant bigger framework, mini-frameworks are, like swimming pools, attractive nuisances. "Hey, look, guys! This is so much simpler!"
> It’s harder to write a framework because it imposes a contract on everything that depends on it.
Judging by what people write and use, I'm not sure this is _exactly_ true. Sure, writing a _good_ framework or library is hard, but people accept piss-poor frameworks, and accept libraries that were designed to work in conjunction with a single framework.
> It’s easier to write a library that is future proofed because it just needs to satisfy its contract.
But the thing is that the library itself defines the contract, and it might be a piss-poor one for many applications.
There is some excellent code out there, and there is a lot of shitty code out there. I think the problem is social; too many people want to write code that is in charge. Now, maybe it's somewhat technical, in that they have used things that are in charge, and they were too big (leading to the mini-framework of the article) or they were otherwise not great, so this leads to yet another framework (cue standards xkcd cartoon) because they realize they need something in charge, but aren't happy with their current options.
And, of course, since the frameworks they know take a kitchen sink mentality, their new framework does as well. (Maybe it's a smaller sink, but everything needed is still shoved in there.) So there are yet more libraries that are tied to yet another framework.
Because writing good libraries that are completely framework independent _can_ be as challenging as writing a good framework. And when someone decides they need a new framework, they are focused on that, and making it work well, and since that drives their thought process, everything else the write gets shoved into the framework.
I was very guilty of this as a young go-getter engineer! Why try to convince another team that something should be fixed if I can just paper over it?
Of course, since their thing is a framework, your wrapper must be a framework too. (Is it possible to wrap a framework into a library?)
The end of the story is even sadder. You work on your replacement and wrapper, and oh no, the framework you are wrapping has problems or slowness because of the framework it depends upon!
I think it could go a little further in explaining what I think the root cause of the issue is: the people developing this mini framework do not have the time or focus to turn it into a full framework. Compare to Django, Rails, React who, whatever your opinion, clearly have time and mission to build, test and document a framework for others to use.
The very nature of working for a SaaS company means your true goal is to build shit for your customers. Any internal tooling has to overcome this large hurdle to get the attention it needs to be able to truly thrive. And rightly so.
These two aren’t really mutually exclusive. Your manager may be extremely friendly and accommodating to you personally (as it seems like the author’s manager was), but part of a manager’s job is growing and supporting their reports with their career goals. If you’ve spent years majorly underleveled like it seems this person did, your manager is failing you. No matter how much of a nice person they might be, they’re not doing their job well if you’re attempting to grow at the company and aren’t succeeding.
So yes, I do think that this person still left a manager. He left a manager who wasn’t meeting the needs he had to stay at the company.
Distributed (multithreaded, concurrent, ...) systems are a counterexample that are highly vulnerable to snake oil. In normal software it makes sense to build up from a small set of intellectually coherent primitives. In those cases you inevitably end up with poor performance and usually reliability if you try that. Java started out with a snake oil approach to threading (synchronized!) and Doug Lea talked some sense into them and now we have java.util.concurrent which has a rich set of primitives which are pragmatic and meet the real requirements, not a vision of purity.
On the other hand, If it was a mini-framework to pound out numerous not-so-simple HTML form applications it could greatly enrich your life and your team's.
I think modern programmers nowadays understand that it is much better to take the path of libraries than frameworks as it provides them with the same functionality of a framework(which is just a bundle of libraries), but with the freedom of implementing their code however they want, unlike wit ha framework, which forces certain structure and style as frameworks had to made certain decisions for the programmer in order to be a functional and comprehensive tool. This lack of freedom will usually bite most programmes LATER, when it is too late to go back and refactor code or change style and whatnot.
And that inherently also makes small frameworks even less usable than the larger ones.
YMMV, but not really.
I keep thinking "Just use GraphQL" because it's basically GQL at this point...except jankier.
Most Spring (+Boot) projects have been far more painful to work with - numerous abstractions and deep and complex relationships between them just to support every technology and integration under the sun. Hard to work with, hard to debug (especially with proxies and how the DI works, alongside the nonsensical rules about how @Transactional works, e.g. how it doesn't if you call a transactional method from within the same component/service), sometimes performs like shit or leaks memory and migrations between major versions are a pain. We just spent multiple months migrating a project from an old Spring version to a more recent version of Spring Boot. It's a pain.
Compare that to Dropwizard: it is fairly stable and most updates are maintenance related. It uses a bunch of idiomatic packages from the ecosystem: Jetty, Jersey, Jackson, Logback, Hibernate/JDBI3, supports Liquibase or Flyway, there's also validation and views or whatever you want, but none of it is pushed down your throat. The docs are practical and more manageable just because it does LESS overall, the code is simpler and there are far fewer surprises. And because the logic is mostly just Java and there's no castle-in-the-sky bullshit with annotations, if you want to swap out HK2 for Dagger (if you still want DI), you can - which I think is good because Dagger also does a lot at compile time and avoids the whole Spring runtime injection can of worms altogether.
The size of a framework doesn't instantly make it good or bad, but oftentimes the bigger ones will be more difficult to reason about and sometimes the amount of abstractions gets out of hand.
The modern variant of this is "platform vs service". At my previous company, it seemed like the only path to promotion was "platform" something something. So every org was in the middle of some way over-budget rewrite of their services as some big bloated platform thing, incompatible with every other team's platform, with less functionality than their old services offered. I don't know why leadership sees all these failures and seems to think "ooh, that's exactly what I want for my team too!" But you can't get a promotion if you're not platformizing.
** mini-frameworks is a realization of the creator's mental model, but it's not everyone's mental model**
People being smart enough to make their own understanding work well - but not smart enough to see they are just pushing their way of doing things and not working on something “generally understood”. A
I am glad they were up front about this. Saved me a read.
Moral of the story, abstractions always fail the edge cases, especially at scale. But when the entire eng org adopts something, it works much better. Everyone has to be bought in. Which at Google scale is hard.
https://research.google/pubs/megastore-providing-scalable-hi...
At the end of the day. You end up inventing a bespoke, worse version of Django anyway.
Those people have their own OKRs and promo desires.
Often times, sending patches to OSS orgs are easier.
So naturally, extension to the original framework happened.
I wonder how much of the problem stated in the article is actually a result of this resume-driven development style? The author says how the mini-framework was pushed by their engineering manager, I can't help but assume the real goal of the project was for the manager and engineers building the framework to have something fancy to show for their next promotion packet.