Vendor lock-in is one of the first risks discussed whenever a company considers using a commercial software platform. What happens if the vendor changes its pricing, shifts the product in the wrong direction, gets acquired, or simply stops serving your needs? What happens if you eventually need to migrate? These are perfectly reasonable questions, and any serious platform evaluation should address them.
What gets discussed much less is another type of lock-in: self-lock-in. This happens when a team traps itself through its own architecture, custom code, internal infrastructure, and accumulated technical debt. Ironically, this often happens precisely because the team originally wanted to avoid depending on an external platform vendor.
Avoiding a Platform Often Means Building One
Let us imagine a team building an IoT or industrial software product. The actual value of the product may come from a fairly specific set of things: domain logic, workflows, analytics, specialized UI, automation rules, integrations with particular equipment, or some other functionality that customers are actually paying for.
The problem is that the product cannot exist on business logic alone. It also needs data acquisition, storage, authentication, authorization, role-based access control, APIs, event processing, multi-tenancy, integration infrastructure, monitoring, reporting, deployment mechanisms, and many other capabilities that have little to do with the unique value of the product itself.
If the team does not use a platform that already provides those things, somebody still has to implement them. Over time, the product team quietly becomes a platform-development team as well. A substantial part of the development budget goes into building infrastructure that is generic by nature but still needs to be designed, tested, secured, documented, upgraded, and maintained internally.
This is where self-lock-in often begins. The infrastructure layer becomes tightly coupled with the application logic, architectural boundaries become less clean, documentation falls behind, developers become dependent on historical knowledge, and every major change requires a deeper understanding of the product core. The company may have successfully avoided vendor lock-in, but it has replaced it with dependency on its own growing internal platform. Within limited budgets and time to market, technical debs grows in parallel.
Imagine Writing an Application without an Operating System
A deliberately exaggerated analogy makes the issue easier to see. Imagine that you need to build a fairly simple desktop application. It reads some data from the network, caches it locally, and shows it in a graphical interface.
Now imagine deciding not to use an operating system.
The application itself may still be simple, but suddenly you have a much bigger problem. You need software that can communicate with network hardware. You need some way to access storage devices. You need display support. You need process management, memory management, security mechanisms, and many other basic capabilities that would normally be provided for you.
Technically, you could write all of this yourself. You would even own every line of code. But very few software companies would consider their own TCP/IP implementation or disk access layer an important competitive advantage. In practice, they would simply have taken responsibility for maintaining a large amount of generic infrastructure that the market already provides cheaply and reliably.
Nobody normally talks about “operating-system lock-in” as a reason to write all of these layers from scratch. Yet one level higher in the software stack, companies sometimes make essentially the same decision when building industrial, IoT, or enterprise applications.
Industrial Automation Already Learned This Lesson
Industrial automation provides an even closer analogy. When engineers need to control a factory, they generally do not begin by writing a SCADA system from scratch. They need to control the manufacturing process, not reinvent all the infrastructure required to build industrial control applications.

A mature SCADA system already provides data acquisition, a historian, alarming, HMI design and runtime, reporting, security, and tools for implementing application logic. Of course, a company could develop all of that internally. Some companies have done exactly that. But in most cases, owning a custom historian or a custom alarm engine does not make the manufacturing process better, nor does it create a meaningful competitive advantage.
This is why the industrial automation industry has been comfortable using SCADA platforms for decades. The same logic increasingly applies to broader IoT and IIoT software development. Generic infrastructure does not become strategically valuable simply because your own developers wrote it.
Self-Lock-In Turns Industry Evolution Into Your Own Backlog
The problem becomes even more visible when the surrounding technology changes. Consider an industrial application that was originally built around classic OPC DA, OPC AE, and OPC HDA. At some point OPC UA appears and starts gaining market share. It is more secure, it is no longer tied to the Microsoft platform in the same way, it provides a richer model, and industrial hardware vendors increasingly prefer it.
If your team owns the entire connectivity stack, OPC UA immediately becomes your own development project. You need to find a suitable software library, integrate it, design a connectivity module around it, connect that module to the rest of your architecture, implement security, optimize performance, make communications resilient, handle real-world failure scenarios, test everything, debug it, and maintain it for years afterwards.
Even if the system is architected well and the connectivity layer is properly decoupled from the rest of the application, this is still substantial engineering work. You have effectively turned an industry-wide technology transition into an item on your internal product roadmap.
With a mature SCADA or industrial IoT platform, the situation is different. A good platform should still allow you to build your own connectivity module if you really need to, but in most cases there is no reason to do so. The platform vendor implements OPC UA support once, improves and tests it across multiple applications and customers, and then makes the capability available to every solution built on top of the platform.
This is one of the hidden costs of self-lock-in. Every new protocol, authentication standard, storage technology, API style, deployment model, or security requirement potentially becomes something your own development team must absorb.
A Good Platform Should Limit Its Own Lock-In
None of this means vendor lock-in is imaginary. It exists, and a poorly designed platform can create a very uncomfortable level of dependency. In my view, a serious platform should therefore be architected from the beginning to keep that dependency as small and survivable as possible.
The first important area is data acquisition. A platform should support extensible drivers for different forms of data access, whether this means polling values, receiving event streams, or invoking remote operations. Storage should be equally flexible, allowing the platform to work with time-series data, relational data, binary data, graph structures, and other storage models without forcing every application into one rigid implementation.
The same principle applies to processing. A platform should allow custom processing modules and extensions to run within the platform’s security, data model, and permission boundaries. The UI layer should allow custom web components and mobile applications rather than limiting developers to a fixed collection of visual widgets.
Data exposure is just as important. A platform should make its internal data and functionality accessible through appropriate external interfaces. Depending on the use case, that can mean REST APIs, MQTT, Kafka, JDBC, OPC UA, or other industrial and enterprise interfaces. Authentication should also be extendable so that the platform can evolve together with changes in enterprise identity infrastructure.
Not everything can be made replaceable. The platform’s core data model, permission system, runtime architecture, and some fundamental internal concepts will naturally remain part of the platform itself. That is the actual area where platform dependency exists.
But there is a major difference between depending on a relatively small, clearly defined platform core and building every surrounding subsystem yourself. Every extension point provided by a mature platform represents one more subsystem that a scratch-built product team would otherwise have to design, implement, test, secure, document, and maintain internally.
What If You Eventually Have to Leave?
This is probably the strongest argument against using a platform. If your application is deeply built around one platform and the vendor eventually becomes unsuitable, migration can be painful. There is no point pretending otherwise.
However, the economics of that migration risk are often looked at from only one side. When you build on a platform, you normally write significantly less infrastructure code. You focus mainly on application-specific functionality instead of implementing the generic stack underneath it.
If the platform relationship fails many years later, some of the work you avoided at the beginning may come back in the form of migration work. You’ll need to replace certain infrastructure functions, rewrite parts of application logic, or reimplement functionality that previously came from the platform.
But a team that chose to build everything from scratch paid much of that cost from day one, often before the product got operationally profitable and while its whole line of business was under strategic risk. It also kept paying for it through ongoing maintenance, testing, security updates, compatibility work, and architectural evolution throughout the life of the product.
In other words, vendor lock-in creates a possible future migration cost, while self-lock-in creates a very real present development and maintenance cost. In the worst case, a platform customer may eventually have to implement some of the infrastructure it previously avoided implementing. The fully custom team has already implemented it, financed it, and committed itself to maintaining it indefinitely.
This does not mean migration risk should simply be accepted. A good platform should let customers retain access to the source code of their own developments, export their data, and extend the system through well-defined interfaces. In some situations, contractual protections such as source-code escrow may also make sense as a catastrophe plan.
But these protections should be viewed for what they are: contingency measures. The normal expectation when selecting a platform is that your application will continue evolving together with the platform rather than that you will eventually be forced to escape from it.
Ownership Is Not Automatically Independence
There is an intuitive appeal to the statement, “If we build it ourselves, at least we own everything”. Technically, that is true. The company owns the code, the architecture, and every internal component.
It also owns every vulnerability, obsolete dependency, protocol upgrade, scaling problem, architectural mistake, regression, compatibility issue, and maintenance task associated with that code. Ownership of software infrastructure is not automatically the same thing as technological independence, and it is certainly not the same thing as competitive advantage.

Sometimes ownership simply means that the problem belongs to you.
So when evaluating a platform, it makes sense to ask how difficult it would be to leave the vendor one day. But that should not be the only question. The equally important question is:
How much platform infrastructure will we have to build and maintain ourselves if we do not use it?
Vendor lock-in deserves attention. Self-lock-in deserves at least as much.
