
BenzyBridge
A standalone-first compatibility layer and include library for FiveM. It detects the framework (ESX / QBCore / QBox / standalone), inventory, money, notifications, on-screen prompts, targeting, and storage that your server is running, and gives every script one unified API for all of them — either in-process as Benzy.* (added to your resource with a single @include), or from outside as exports.BenzyBridge:*. Write a script against the bridge once and it runs the same on a bare standalone server or a full framework stack: every concern degrades gracefully, so nothing is a hard dependency.
Made by Samuel Benzy of Benzy Development.
Features
- One unified API — player identity, job/gang, money, inventory, access control, notifications, on-screen prompts, targeting, and storage, all through a single surface.
- In-process include — a consumer adds one
shared_scriptand callsBenzy.*directly: a normal Lua call in its own state, with no cross-resource export hop. - Auto-detection — every concern defaults to
autoand binds to the first supported provider that is running; force a specific one whenever you like. - Multi-framework — normalizes ESX, QBCore, QBox, and standalone into the same player/job/money shape, so your script never branches on the framework.
- Standalone-first — no framework and no hard dependencies. Every concern has a safe, working answer when nothing is installed.
- Provider-agnostic — a script written against the bridge keeps working when you swap the underlying notify / money / prompt / targeting system.
- Extensible — point notifications or prompts at any resource with a custom hook, or register a money adapter at runtime, then select it by name.
- One storage connection — auto-detects oxmysql or mysql-async and hands out a single query API, or falls back to file mode; each resource keeps its own tables.
- Headless — no NUI of its own; it routes to the resources that draw, with a built-in
native/chatfallback so a prompt or toast is never silently lost.
How it works
The include model
A consumer adds, as its first shared script:
shared_script '@BenzyBridge/init.lua'
and (optionally) declares dependency 'BenzyBridge'. init.lua runs inside the consumer's own Lua state, reads the resolved stack via exports.BenzyBridge:GetSettings(), loads the active framework / inventory / targeting adapters in-process, and builds one global table, Benzy. The consumer then calls Benzy.* directly — a plain Lua call with no export hop. Nothing is a bare global except Benzy itself, so it never collides with your own helpers.
-- Server: normalized across ESX / QBCore / QBox / standalone
local player = Benzy.GetPlayer(src)
Benzy.AddMoney(src, 'cash', 500, 'Reward')
if Benzy.HasItem(src, 'water', 1) then Benzy.RemoveItem(src, 'water', 1) end
Benzy.Notify(src, 'success', 'Shop', 'Purchase complete', 4000)
Auto-detection
On first call (cached, and re-resolved whenever a resource starts or stops) the bridge resolves each concern from your config.lua plus what is actually running:
| Concern | auto resolves to |
|---|---|
| Framework | es_extended → esx, qbx_core → qbox, qb-core → qbcore, else standalone |
| Inventory | ox_inventory → qb-inventory → qs-inventory, else none |
| Money | a framework's own money if a framework is active, else BenzyMoney, else none |
| Notify | BenzyNotifications, else the built-in native feed |
| Draw-text | BenzyDrawText, else the built-in native prompt |
| Targeting | ox_target → qb-target, else none |
| Storage | oxmysql → mysql-async, else file |
Standalone-first degradation
Every concern has a safe answer when its provider is absent — running without one is a normal, supported setup, never an error:
- No framework → a standalone player identity (Rockstar license + name) and a default job; identity and access still work.
- No inventory → item operations are silent no-ops.
Benzy.HasInventory()returnsfalseand your script keeps its own database tracking (e.g. a counter). This never warns. - No money provider (or
Config.Money = 'none') → every money call returnsfalse, 'UNSUPPORTED', so a script that supports running without money degrades cleanly. On a framework money provider only the core cash/bank subset works; the rest returnfalse, 'UNSUPPORTED'. On BenzyMoney the whole surface works. - No targeting →
Benzy.ResolveInteraction('target')downgrades a script to draw-text prompts and prints a one-time console warning, so targeting is never forced on a server that has none. - No notify / prompt provider → a built-in
native(game feed / help-text) orchatfallback renders instead, so a toast or prompt is never lost.
Requirements
- A FiveM server (
fx_version 'cerulean'). - (Optional) A framework — ESX, QBCore, or QBox. None required; standalone is fully supported.
- (Optional) A SQL connector — oxmysql or mysql-async — only if a resource asks the bridge to use a database. Without one, storage runs in file mode.
- (Optional) Providers — an inventory, money, notification, draw-text, or targeting resource for the bridge to route to. Each is detected at runtime; anything missing falls back.
Installation
-
Place the
BenzyBridgefolder in your server'sresourcesdirectory. -
Add it to
server.cfgin the right order: your SQL connector and framework first, then BenzyBridge, then the providers it routes to, then the consumer resources that use it.ensure oxmysql # SQL connector (only if you use a database)ensure es_extended # your framework (skip on a standalone server)ensure BenzyBridge # the bridge — after the framework/connector, before providersensure BenzyMoney # providers the bridge should route toensure BenzyNotificationsensure ox_target# ... your resources that call Benzy.* / exports.BenzyBridge:* ... -
Open
config.luaand set the services + storage (all default toauto). -
Restart the server. On boot the bridge prints the resolved stack to the server console.
Load order matters.
autobinds to a provider only if that provider is started before the caller. If a call resolves to a fallback you didn't expect, check the order inserver.cfg.
Configuration
Everything is in config.lua, and every option lists its accepted values inline on the same line.
| Option | Values | What it does |
|---|---|---|
Config.Debug | true | false | Prints resolution + routing diagnostics to the server console and each client's F8. Leave off on a live server. |
Config.Framework | auto | esx | qbcore | qbox | standalone | The core to integrate with for player/job/money. |
Config.Notify | auto | BenzyNotifications | chat | native | custom | none | Which system shows notifications. |
Config.DrawText | auto | BenzyDrawText | native | custom | none | Which system shows on-screen prompts. |
Config.Target | auto | ox_target | qb-target | none | Which targeting system backs Benzy.Target.* (separate from prompts). |
Config.Money | auto | esx | qbcore | qbox | BenzyMoney | custom | none | Which system handles balances / payments. none turns money off on purpose (every money call returns UNSUPPORTED). |
Config.Inventory | auto | ox_inventory | qb-inventory | qs-inventory | none | Which inventory backs item operations. none makes item ops silent no-ops. |
Config.Storage | auto | oxmysql | mysql-async | file | How resources persist data. |
Config.Custom | { Notify = {…}, DrawText = {…} } | Hooks used when the matching option above is custom — a { Resource, Export, Event } set, resolved in order Fn → Export → Event. A custom money system is registered as an adapter instead (see the Integrations documentation). |
Config.Locale | en | Language for the bridge's console / diagnostic text. Add locales/<code>.lua (it loads automatically), then set the code here. |
autouses the first supported provider that is running, else a safe fallback (nativefor notify / draw-text,nonefor targeting and money,filefor storage). To route throughConfig.Custom, set the option tocustomexplicitly.customroutes notifications / prompts throughConfig.Custom.
Interaction: draw-text vs targeting
The bridge treats on-screen prompts and targeting as two separate concerns, controlled independently:
Config.DrawText— the "press E" style help-text / prompt system (Benzy.Show/Benzy.Hide).Config.Target— the eye/target system (Benzy.Target.*).
Each consumer picks per-script which style it wants. A script that prefers targeting calls Benzy.ResolveInteraction('target'): if a targeting system is running it returns 'target', otherwise it warns once and returns 'drawtext' so the script falls back to prompts. This way a server without a targeting system still works, and a script never forces one on you.
Commands
debugbridge— prints the full resolved stack: framework, language, and what backs each concern (money, inventory, notify, draw-text, target, storage), plus a live database probe server-side. Run it in the server console, or in a player's F8 console. In F8 it works only whenConfig.Debug = true— otherwise it just tells you to enable it — so ordinary players can't probe your setup.
On boot the bridge also prints the resolved stack to the server console.
What works with and without a framework / inventory / money
Everything in the Standalone column works on a bare server with nothing installed. Adding a framework, inventory, or money provider upgrades those rows — no change to the scripts that call the bridge.
| Capability | Standalone (nothing installed) | + Framework (ESX / QBCore / QBox) | + Inventory | + Money provider |
|---|---|---|---|---|
Player identity (GetPlayer, GetLicense, GetName, IsLoaded) | ✅ license + name | ✅ full normalized record (job, gang, money) | — | — |
Job / gang (GetJob, GetGang, HasJob, OnDuty) | ✅ default job | ✅ real job/gang + duty | — | — |
Access control (HasAccess) | ✅ via ACE / identifiers / Discord | ✅ also framework job/group | — | — |
Notifications & prompts (Notify, Show) | ✅ native / chat fallback | — | — | — |
Targeting (Benzy.Target.*) | ⚠️ downgrades to draw-text (needs ox_target / qb-target) | — | — | — |
Item operations (HasItem, AddItem, RemoveItem, CanCarry) | ⚪ silent no-op (HasInventory() = false) | — | ✅ real item ops | — |
Money reads / mutators (GetCash, AddMoney, …) | ⚪ false, 'UNSUPPORTED' | ✅ core cash/bank subset | — | ✅ full surface on BenzyMoney |
Storage (Query, Insert, …) | ✅ file mode | — | — | — (a SQL connector switches storage to database mode) |
✅ works · ⚠️ works with a documented fallback · ⚪ safe, intentional no-op
Integrating
- the Integrations documentation — adding the bridge to a resource, what it auto-detects, storage, and registering a custom notification / prompt / money system.
Notes
- Integrating from outside the suite — a third-party resource calls the script it actually wants (
exports.BenzyMoney:*,exports.BenzyFuel:*, …) and listens to that script's events. The bridge is what lets those scripts run on whatever framework / inventory / money system you have; it isn't an API layer for outside code. - Each provider script keeps all of its own logic and works standalone; the bridge only routes to it.
- Server-authoritative — money, inventory, and access checks are validated server-side; a client never sets a balance or grants itself an item.
- The whole bridge folder ships escrow-open on purpose — the include model reads its own files, which cannot be encrypted. Your individual scripts stay encrypted on their own.
Troubleshooting
- Turn on debug first — set
Config.Debug = true, restart, and read the boot summary + thedebugbridgeoutput. - A call does nothing / resolves to a fallback — check what each concern resolved to.
autoneeds the provider started before the caller; fix the order inserver.cfg. - Money returns
UNSUPPORTED— no money provider resolved, orConfig.Money = 'none'(which forces this on purpose). Start a provider (e.g. BenzyMoney), register a custom adapter, or setConfig.Moneyto one that is running. On a framework money provider, non-core operations return this by design. - Item ops do nothing and there's no warning — that's the intended no-inventory behavior. Branch on
Benzy.HasInventory()and use your own database tracking when it'sfalse. - Targeting isn't working — no targeting system is running, so
Benzy.ResolveInteractionfell back to draw-text (it warns once). Start ox_target / qb-target, or set the script to draw-text to silence it. - Queries return
nil— storage is in file mode (no connector), or a forced connector isn't started. Checkdebugbridge.
Support
Need help? Visit support.benzy.lol.
Credits
Made by Samuel Benzy of Benzy Development.
Website: https://benzy.lol