Ever looked at code that feels more like a framework demo than a real product?
Many teams proudly say: “We’ve built an independent product.”
But when you dig deeper, you realize everything — from routing to authentication — is tightly bound to the framework.
Why is this a problem?
In that scenario, your product has no independent identity.
If the framework gets deprecated tomorrow or the team shifts direction, you’ll end up rewriting everything from scratch.
That’s the danger of Framework Lock-In.
The trade-off
On the flip side, some teams intentionally give up freedom for development speed and community support.
Fair enough… but is that truly a strategy, or just convenience disguised as one?
What often gets forgotten
A real product should have its own architectural identity.
A framework should remain a tool, not the thing that defines your product.
The uncomfortable truth: many so-called “products” are really just framework extensions.
Question
Would your product survive without the framework,
or is it just a plug-in living on top of it?
What do you think?
Have you ever refactored a system that was too tied to its framework?
Top comments (4)
I understand the gripe you want to address.
I think using a framework because it is popular is one of the reasons people stick with the framework conventions instead of thinking about the needs of the application.
If you want to check out a framework, it is best to do it as a proof of concept.
When you start a project and a framework fits a lot of the needs of the application, I don't think it is bad to write more framework code. The faster the application is used, the faster the teething problems appear.
During the improvement process the code will go from framework code to more independent code.
That’s a solid point — starting close to the framework can indeed accelerate feedback loops and get a product into users’ hands faster.
What I wanted to highlight, though, is that many teams never exit that early phase. The “temporary coupling” to the framework often becomes structural debt when boundaries aren’t revisited.
Frameworks are great accelerators, but at some point the product needs its own spine — domain logic and architecture that can survive even if the framework or language changes.
In one of my recent projects, this exact concern led me to build a custom ORM and QueryBuilder from scratch. The goal wasn’t to reinvent the wheel, but to keep the Core completely framework-independent so that future framework or language migrations wouldn’t require rewriting the business logic. I’ll share the full story in my next dev.to post.
I agree a lot of projects fall in the framework code trap. But that is not a framework problem, but a developer and management problem.
While framework independence is a good thing, I don't think it is necessary for every project.
It is not a bad thing to depend on third party code. Instead of building an ORM you could analyse your ORM requirements and check them against all solutions are available.
The abstractions of the domain logic and architecture can be language agnostic. But if you have implemented them in one language, you can't use that code in another language.
In short, it is good you think about application from a higher viewpoint, but you should be able to make compromises between code purity and efficiency per project.
That’s a great perspective — I agree that frameworks themselves aren’t the real problem; the issue is usually how teams and management use them. Framework independence isn’t a universal rule, and full decoupling is rarely justified for small or short-lived projects.
The idea I wanted to explore is that independence isn’t about avoiding third-party tools, but about retaining architectural control when the product has a long lifespan, multiple teams, or an evolving tech stack. In those cases, clear boundaries let the framework serve the architecture rather than define it.
And yes, you’re absolutely right that code written in one language can’t simply be reused in another — that’s not the intent. The focus is on portability of contracts and behavior, not literal source reuse.
By expressing domain rules through explicit interfaces, schemas, and shared test suites, we can make re-implementation in another language a mechanical process rather than a risky rewrite.
So it’s not a matter of purity versus pragmatism; it’s about designing the right boundaries so that pragmatism today doesn’t become technical debt tomorrow.