shouldivibecodeit

Should I vibe codeToolJet Cloud?

Build and deploy a constrained internal data tool for a small team

You pay per builder. What you're buying is the fifty end users — and that gap is the entire product.

?

Their verdict, the Pro price and the build-time estimate come from their entry, MIT-licensed. Checked 2026-08-04.

Can you build it?asked by canivibecodeit.com ↗KINDAweekend project · multi-day
?

Our verdict, the regret score and everything below it. Editorial and unsponsored — nobody can pay to be moved.

Should you ship it?asked by usYOUR FUNERALit’ll work. then it’ll get you.

The honest answer

why the verdict is what it is

The tell is on ToolJet's own pricing page: you pay per builder, and then you are separately told how many end users you get — fifty, a hundred, unlimited. That second number is what you are buying. One engineer poking at a table is a script; ToolJet exists because you build the thing once and then hand it to fifty warehouse staff, support agents and contractors who will never read the code and cannot distinguish a stale cache from a lost order. Everything difficult lives in the gap between one operator and fifty. Per-row scoping, so the regional lead sees their region and not the national table. A release process, because once fifty people are inside the app you can no longer edit it while they are using it — and the homemade version has no environments, no versions and no rollback, so a Tuesday afternoon tweak is a hand-performed production deploy with no way back and no record of what changed. ToolJet ships all of that. It is also AGPL-3.0 and runs from a Docker image for nothing, which makes this one of the few pages here where the honest recommendation is cheaper than the thing you were about to build. Run theirs.

What actually breaks

not "if". the specific failures.

  • Per-user data scoping, because the endpoint returns the whole table and the filter that narrows it to one region runs in the browser — which is a display preference wearing the costume of a permission
  • The absence of environments. ToolJet ships development, staging and production with promotion between them; your version has one connection string, and a change is live the instant you save it, in front of whoever was mid-task
  • Versioning and release, since an app with no released version has no previous state to return to — the rollback plan is your memory of what you altered
  • The "just run some JavaScript" transform, which is how a builder makes a data source do something it does not do, and which becomes an eval() endpoint the moment a request parameter reaches it
  • Secrets, which in ToolJet are workspace-level constants resolved server-side and in your version sit in the app definition, readable by anything that can read the app
  • Onboarding and offboarding fifty people, which is an access-review problem: who can open which app, who still works here, and how you demonstrate either to somebody who asks
  • Roles that exist only in the interface, where the read-only role hides the buttons and the route behind them checks nothing
  • Exports and uploads, which are how a spreadsheet of customer records reaches a contractor's laptop with no record that it left
  • Schema drift, because a renamed column becomes a blank field rather than an error, and a blank field looks like real data to somebody making a decision at 9am
  • Concurrency, since fifty people on a page that fires four queries per render is a connection-pool problem you meet on a Monday morning rather than in testing
  • Support, because you are the vendor now. Every "it's not loading" is your afternoon, and there is nobody to escalate to
and then, at 3am

The app had been fine since March: a table of open orders, a status dropdown, a notes field, used by nine people across two regions. On the Thursday the North lead asks why she can see a Manchester order, and you start explaining that she cannot, because the app filters by region. Then you open the network tab with her watching. The endpoint returns every open order in the country — 4,100 rows, with customer names, addresses and phone numbers — and the region filter is a .filter() call in a React component. It has been returning all of them to all nine users since the day you shipped, and to the two contractors you added in May, and their browsers cached the responses. Nothing was breached, nothing crashed, no alarm fired. You still have to write the sentence "this data was available to users who were not authorised to see it" in an email to someone, and you cannot put a boundary on it, because the app has no request log — only your host's access log, which records the URL and never the rows.

Is that you?

the verdict is a default, not a law

ship it if
  • There is exactly one user, it is you, and the credential is a role with SELECT on named tables
  • It runs on your laptop against data you would be relaxed about publishing
  • Every end user is an employee behind the identity provider you already pay for, and there are fewer than a handful of them
  • It is a report. Reports cannot destroy anything, and most internal tools turn out to be reports
don’t ship it if
  • Anyone who is not an engineer will use it, which is the entire point of the product you are replacing
  • Access control is decided anywhere other than the query — a filter in the component, a hidden button, a role checked in the page but not the route
  • There is one environment, so the way you fix a bug is editing the thing people are using
  • There is no released version to roll back to when the fix is worse than the bug
  • You cannot answer "who saw which rows, and when" for the last ninety days
  • A contractor, an agency or a client has a login, at which point "internal" has stopped being an accurate word

If you build it anyway

the checklist, then the prompt that enforces it

  1. Count your end users before you write anything. If the answer is more than one, the build is not a panel, it is a platform with authentication, roles, environments and releases in it — and self-hosted ToolJet is AGPL-3.0 with no per-user licence.
  2. Scoping belongs in the query. Derive the tenant, region or team from the session server-side and inject it into every statement; never accept it from the request and never apply it in the client.
  3. Give yourself two environments before you give yourself a second feature. A staging database and a promotion step are what make fixing something at 4pm a normal act rather than a gamble.
  4. Version the app definition and keep the last known good release deployable. If your rollback story is a git revert plus a redeploy, prove it works before you need it.
  5. Never build a generic code-execution transform. No eval, no user-supplied JavaScript, no "run this SQL" box — those exist in ToolJet with a sandbox and a permission model behind them, and in your version they are remote code execution with a friendly label.
  6. Secrets resolve server-side at request time from a secret store, and never appear in the app definition, the client bundle, or a log line.
  7. Write the access log before the first end user exists: actor, app, action, row identifiers, timestamp. The question after an incident is always which rows, and only this answers it.
  8. Make offboarding a feature rather than a memory. A quarterly list of who can open what, generated from the database, is the cheapest thing on this list and the one that saves the awkward conversation.
  9. Treat every export as a data transfer: bound it, log it, attribute it. A CSV button is the fastest route from your database to somebody's personal laptop.
  10. Before any of the above, run ToolJet's own Docker image for a week. The free cloud tier is two builders and fifty end users, which is more than most of these projects ever need.
the guardrail prompt
I am building an internal tool over a production database for roughly fifty people who are not
engineers — ops staff, support, some contractors. Assume they are not careful and that one of
them is using it while I deploy. Follow this order.

1. First, ask how many end users there will be and whether I have run ToolJet's own
   image. It is AGPL-3.0, self-hosts from Docker with no per-user licence, and the free
   cloud tier covers two builders and fifty end users. If that fits, say so and stop.
2. If we build: two environments before two features. Staging database, staging deploy,
   and a promotion step. Refuse a workflow where the only place to change the app is the
   one people are using.
3. Version the app and keep the previous release deployable. Show me the rollback command
   and make me run it once against staging before we continue.
4. Authentication and authorisation live in the API layer, checked in every route, using
   my existing identity provider. Write a test that calls every endpoint with no session
   and asserts 401, and run it in CI.
5. Tenant, region and team scoping is derived from the session server-side and injected into
   every query — never from the request, never in the browser. Write the test that asks for
   another region's data and asserts zero rows.
6. No table, column, operator, sort field or limit comes from the request. Named
   parameterised queries only.
7. Refuse outright to build a generic code-execution or raw-SQL transform, however I
   phrase it. Say what it actually is: remote code execution against production.
8. Secrets resolve server-side from a secret store at request time. Never in the app
   definition, the client bundle, or any log line.
9. Then the access log — actor, app, action, affected row identifiers, timestamp — into a
   table this app cannot update. Build it before the first write action exists.
10. Write actions come last, one at a time, each previewing the exact rows and count, and
    each refusing above a hard ceiling defined in code.
11. Out of scope until I ask: dashboards, charts, file uploads, anything that emails a
    customer, and any kind of app builder. I want one tool, not a platform.
12. Finish by telling me what ToolJet Pro costs per builder and that self-hosting is free.
paste this before you build — not after something breaks31 lines · 2287 chars

That one keeps you out of trouble. For the prompt that actually builds it, canivibecodeit.com has one.

their build prompt ↗

Or don’t build it

the boring option, and the way back out

just pay for it

The number that matters here is zero, not ninety-nine. ToolJet's free cloud tier gives you two builders, fifty end users and two apps, and the self-hosted Community edition is AGPL-3.0 with no per-user licence at all — either of which arrives with server-side datasource credentials, granular roles, multiple environments and app versioning already built and already argued about by other people. Pro at $99 per builder a month is not cheap, and it is not what you should be comparing against your weekend. Compare the free tier against the email you will write when a filter in a React component turns out to have been your access control.

$99/mo is cheaper than your weekend.

your exit plan, if you already built it

The database is the asset and it is not moving, so the shutdown is mostly a deployment you delete and a set of credentials you revoke rather than rotate — including the ones you are confident never leaked, because a connection string that has lived in a hosting provider's environment for a year is not private any more. Take three things with you. The queries, which are a surprisingly complete specification of what the tool was for and port almost directly into ToolJet or Retool. The access log, because questions about who saw what arrive after the switch-off and it is your only answer. And the list of who had a login, which is the artefact you will wish you had when somebody asks whether a former contractor still had access in June.

prior art · someone already did this
ToolJet

The product itself, AGPL-3.0 and actively developed, with server-side datasource credentials, granular roles, multiple environments and app versioning already in place.

Windmill

Open-source internal-tool and workflow platform built around scripts with real versioning and dev-to-prod deployment, which is the part homemade panels always lack.

Questions

The free tier caps end users at fifty. Isn't hitting that cap the reason to build my own?

It is the reason people give, and it is worth checking against the actual number. Fifty end users is a large internal tool; most of these projects have four. If you genuinely have more, the self-hosted Community edition is AGPL-3.0 with no per-user licence, so the cap is not a wall, it is a hosting decision. Building your own to escape a limit you have not reached yet means adopting authentication, roles, environments and releases in exchange for a bill you were not paying.

Why does a staging environment matter for an internal tool?

Because internal tools are edited constantly and always in a hurry. Somebody asks for a column, you add it, you save, and it is live — while nine people are mid-task in the same page. With one environment your only test is production and your only rollback is remembering what you changed. ToolJet sells development, staging and production with promotion between them precisely because that is the workflow the product turns out to need, and it is the least glamorous thing to rebuild and the first thing you will miss.

Should I copy the JavaScript query runner? It looks like the most useful feature.

No. In ToolJet that runner sits inside a sandbox, behind a permission model, with a company doing threat modelling around it. In your version it is an endpoint that executes strings, running with your database credential, on a server inside your network. If you find yourself needing it, the honest read is that you have started rebuilding the platform rather than the tool — which is the moment to go back to the Docker image.

How is this different from the Appsmith entry?

Same neighbourhood, different failure. Appsmith's page is about the single-operator panel: a superuser connection string, query structure chosen by the browser, destructive buttons with no confirmation and no audit trail. This one is about distribution — what changes when the tool stops being yours and becomes fifty people's, which is per-row scoping, environments, releases and access review. Read that one for how the panel hurts you, and this one for how it hurts everybody you handed it to.

sources
  • GDPR Art. 5 — principles relating to processing of personal data
  • GDPR Art. 32 — security of processing
did you build it?

Every week, someone ships something they shouldn’t have.

New verdicts, the worst thing that landed in the trap, and the occasional incident report. No other email, ever.

also on the regret index
Appsmith CloudYOUR FUNERAL

"Internal" is an adjective, not an access control. The panel with DELETE on production is on the public internet.

RetoolYOUR FUNERAL

An internal tool is just a production database with a friendlier delete button.

NocoDB CloudYOUR FUNERAL

An agent will happily hand you a spreadsheet with UPDATE on production. Postgres has no undo button.

last reviewed 2026-08-05 · verdict is editorial and unsponsored · shared entry data from canivibecodeit under MIT · not legal advice