Developers have a reflex about low-code, and it isn't respect. Some of that is defensiveness, but a good deal of it is earned engineering judgement — low-code platforms genuinely are bad at things developers correctly care about.
The useful framing isn't "is low-code good?" It's: your team can build a finite number of things well. Which of them deserve to be built by hand? Some of the software your company needs has no business consuming a sprint. Getting that allocation right is the whole game.
What "low-code" actually covers
The term is nearly useless because it spans very different categories. Sort them by what they replace:
Internal tool builders — Retool, Appsmith, Budibase, ToolJet. Drag-and-drop UI bound to queries against your data. They replace the admin panel you keep not building.
Backend-as-a-service — Supabase, Firebase. Not usually filed under low-code, but they belong here: they eliminate the auth system, the CRUD API, and the realtime layer you'd otherwise write. Supabase is a managed PostgreSQL with an auto-generated API and row-level security; Firebase is a document store with SDKs and a mature mobile story.
Instant API layers — Directus, Hasura, NocoDB. Point them at an existing database and get an API and an admin UI. Hasura in particular exposes a GraphQL API over your schema with permissions attached, which is a lot of code you don't write.
Workflow automation — n8n, Zapier, Make. Glue between services.
These have different risk profiles. Conflating them is why the debate goes nowhere.
The real predictor: value density vs interface uniqueness
Here's the model I'd actually use.
Every piece of software you build has business value and requires some degree of interface uniqueness. Low-code is spectacular where value is high and uniqueness is near zero — and destructive where uniqueness is the value.
- Admin panel for your support team. Huge value: support resolves tickets faster every single day. Uniqueness required: none whatsoever. Nobody has ever churned because the refund tool wasn't beautiful. Perfect low-code fit.
- Your product's core workflow. Huge value, and the interaction design is the differentiation. Build it. Obviously.
- An internal dashboard three people check weekly. Modest value, no uniqueness. Low-code — or a spreadsheet, honestly.
The best low-code use case is the tool you've been meaning to build for eight months and keep deprioritising — because that decision was correct every single time you made it.
That last case is the honest heart of it. That admin tool never wins against product work, and it never will. Low-code isn't competing with the polished internal tool your team would build. It's competing with the thing that doesn't exist, and the manual database queries someone runs in the meantime — in production, by hand, with no audit trail. That comparison is where low-code wins overwhelmingly, and it's the comparison people skip.
The engineering objections, taken seriously
This is where most low-code advocacy hand-waves. Let's not.
Version control barely works
Most low-code platforms store your application as rows in their own database, not files on disk. The consequences cascade:
- No meaningful diff. "What changed in this app last Tuesday?" often has no good answer.
- No pull request. Review as an engineering practice mostly evaporates.
- No blame. Something broke; the platform may tell you who last saved, not what they changed.
- Merge conflicts are undefined. Two people editing one app usually means last-write-wins.
Some platforms do better — several offer Git-backed source control that serialises apps to JSON, and self-hosted options generally let you export definitions. Treat this as a hard filter. Before adopting anything, ask: can I get the application definition into Git, and can I diff it? If not, you're accepting that a category of engineering discipline doesn't apply to this system. That might be fine for a dashboard. It's not fine for anything you'd be upset to lose.
Testing is mostly absent
There's typically no unit test story. Your automated test options range from "browser tests against the rendered UI" to "none." For a support tool, acceptable. For anything computing money, that should stop you cold.
Environments and promotion
Dev, staging, and production are foundational assumptions in normal engineering and an add-on feature in low-code. Some platforms handle it well; others expect you to click carefully in production and hope. Check before you build, not after.
Local development
You generally can't. You're editing in a browser against a running service. No offline work, no local branch, no experimentation without consequence.
The most damaging low-code pattern is pointing the tool straight at your production database and writing UPDATE statements in the UI.
It works immediately, which is why people do it. But now your business rules live in two places: your application, and a query box inside a tool with no tests and no code review. Every invariant your API enforces — validation, audit logging, cache invalidation, side effects like "email the customer when a refund posts" — is silently bypassed. The bug this produces surfaces months later as data that shouldn't exist, and nobody remembers the tool did it.
The architecture that fixes most of this
The trap above points directly at the solution, and it's the most valuable idea here.
Put your business logic behind an API you own. Let the low-code tool be a thin, disposable UI over it. Then the platform's weaknesses stop mattering — because nothing important lives inside it.
Instead of the low-code app writing to your database:
[ Low-code UI ] ---> [ your database ] ✗ logic bypassed, rules unenforced
Have it call the same API your product uses:
[ Low-code UI ] ---> [ your API ] ---> [ your database ]
^
validation, authz, audit log,
side effects — all still enforced
In practice, a refund button in an internal tool should be a POST to an endpoint you wrote and tested:
// Query in an internal tool builder — calling your own API,
// not touching the database directly.
// POST https://api.internal.example.com/refunds
{
"order_id": "{{ ordersTable.selectedRow.id }}",
"amount_cents": "{{ refundForm.data.amount * 100 }}",
"reason": "{{ refundForm.data.reason }}",
"actor": "{{ currentUser.email }}"
}
Your API validates the amount against the original charge, checks that this user may issue refunds, writes an audit record, calls the payment provider, and emails the customer. The low-code tool renders a form and a table. That's all it does — and that's all you ever want it to do.
The payoff is that the platform becomes disposable. If pricing changes, if the vendor is acquired, if you outgrow it — you rebuild a form against an API that already exists. That's days of work, not a migration project. You've converted lock-in into a UI you can throw away.
This same principle is why BaaS platforms deserve care. Supabase's row-level security is a genuinely good mechanism for enforcing authorization at the data layer, which mitigates a lot of the "client talks straight to the database" concern — but RLS policies are security-critical code, and they need review and testing like any other. Getting them wrong is an authorization bug with the reach of your whole table.
Open-source options worth knowing
Self-hostable matters here beyond ideology: it means you can put the tool inside your network next to your data, and it means an export path exists.
- Appsmith — internal tools, connects to most databases and APIs, JavaScript available anywhere you need real logic. Self-hostable with Docker.
- Budibase — internal apps and CRUD, bundles its own database if you don't have one, with built-in automations.
- ToolJet — comparable to Appsmith; a low-code app builder with a broad set of data connectors.
- NocoDB — turns an existing SQL database into a spreadsheet-like interface. Excellent when the users are non-technical and the shape of the work is genuinely tabular.
- Directus — wraps an existing SQL database with a REST/GraphQL API and an admin app, without imposing its own schema. Notably good when the database already exists and you refuse to let a tool own it.
The commercial options — Retool foremost — are more polished and often faster to a result. The trade is the usual one: per-seat pricing, and someone else's roadmap.
A checklist before you commit
Ask these five questions. The answers predict the next two years better than any feature comparison:
- Is this internal or customer-facing? Internal is where low-code earns its keep. Customer-facing needs a much stronger justification than "it's faster."
- Where will the business logic live? If the answer is "in the platform," reconsider. If it's "in an API we own," proceed cheerfully.
- Can I get the app definition into Git? If not, cap the blast radius accordingly.
- What's the exit path? Not "will we leave," but "what does leaving cost, in weeks?" Answer it before you build, while you're still allowed to walk away.
- Who maintains this in a year? Low-code tools grow the same maintenance burden as real software, because they are real software — just software you can't grep.
When to just write the code
Say no to low-code when:
- It's your product's differentiator. If the interaction is the value, a platform's component library will constrain you exactly where you most need freedom.
- The domain logic is genuinely complex. Past a threshold, you're writing all the logic anyway — in a worse editor, without tests, inside someone else's runtime. You've taken the constraints and abandoned the benefit.
- It must be correct. Payroll, billing, anything regulated. You want tests, review, and history.
- It's performance-critical or high-traffic. These platforms optimise for build speed, not throughput.
- The requirements are still moving fast. Low-code is great at the 80% and disproportionately painful in the last 20%. If you can't yet see the shape of the thing, you can't know whether you're about to land in that 20%.
The bottom line
Low-code isn't a threat to your job, and it isn't a magic accelerator. It's a tool with a genuinely narrow sweet spot: software with real value and no need to be special.
Most engineering organisations have more of that than they admit — admin panels, back-office tools, data-entry screens, one-off dashboards — and most are quietly paying for it in manual production queries and tools that never get built.
Use low-code there. Keep your logic in an API you own so the tool stays disposable. Build your product by hand. And if you're unsure: prototype in low-code, learn what the thing actually needs to do, and rebuild it properly if it earns that. The prototype was never wasted — knowing the requirements was always the hard part.