ScriptsAboutBlogToolsKnowledge BaseReviewsFAQBasketDocsSupport
Frameworks

What is QBCore? A Beginner's Guide to the FiveM Framework

If you've spent any time around FiveM roleplay, you've heard the name QBCore. It's one of the two dominant frameworks (alongside ESX) and powers a huge number of modern roleplay servers. But if you're just starting out, "framework" and "QBCore" can feel like jargon. This guide explains what QBCore actually is, how it fits together, and the handful of code patterns you'll use every day.

What a framework is, and why you need one

Without a framework, every script on your server would have to invent its own answer to the same questions. What is money? Where is it stored? What job does this player have? How do I know if they're on duty?

Twenty scripts each answering those questions differently gives you twenty incompatible systems. Your police job would not know about the money your shop script created.

A framework is the shared answer. It owns players, money, jobs and items, and every script asks *it* rather than deciding alone. That is what makes a coherent server possible.

What QBCore is

QBCore is a free, open-source framework for FiveM. It manages:

  • Players โ€” identity, character data, and metadata
  • Money โ€” cash, bank balances, and transactions
  • Jobs โ€” police, EMS, mechanic, and custom jobs with grades
  • Items and inventory โ€” what players carry and own
  • A shared event and callback system โ€” so scripts can work together

The core resource: qb-core

At the heart of it is a resource called qb-core. This is the framework itself. Everything else โ€” qb-policejob, qb-garages, qb-shops โ€” is a separate resource that depends on qb-core being loaded first.

Load order matters. In server.cfg, qb-core must start before anything that uses it:

ensure qb-core
ensure qb-multicharacter
ensure qb-spawn
# everything else after

Getting this wrong produces attempt to index a nil value (global 'QBCore') on boot โ€” the single most common QBCore starting error, covered in our nil value guide.

The patterns you'll use daily

Almost every QBCore script you read or write uses these four. Learning them is most of the learning curve.

Getting the core object:

local QBCore = exports['qb-core']:GetCoreObject()

Both client and server. If you see the older TriggerEvent('QBCore:GetObject', ...) wait-loop pattern in a script, that resource is dated.

Getting a player, server-side:

local Player = QBCore.Functions.GetPlayer(source)
if not Player then return end

print(Player.PlayerData.charinfo.firstname)
print(Player.PlayerData.job.name)
print(Player.PlayerData.money.cash)

Always check if not Player then return end. source can refer to a player who has already disconnected, and skipping that check is how you get nil errors under load.

Money:

Player.Functions.AddMoney('bank', 500, 'paycheck')
Player.Functions.RemoveMoney('cash', 100, 'shop-purchase')

That third argument is a reason string. It appears in logs, and it is the difference between an economy you can audit and one you cannot.

Jobs:

Player.Functions.SetJob('police', 2)

if Player.PlayerData.job.name == 'police' and Player.PlayerData.job.onduty then
    -- on-duty officers only
end

Reference pages for QBCore.Functions.GetPlayer, Player.Functions.AddItem and Player.Functions.SetJob cover the full signatures.

Client and server: the split that catches everyone

QBCore runs on both sides, and they do not have the same powers.

  • Client knows about the local player and the world they can see. It cannot be trusted.
  • Server owns the truth โ€” money, jobs, items โ€” and is the only side allowed to change them.

The rule that follows: never let the client decide something valuable. A client event that says "give me $5000" will be called by a cheater within a week. The server must validate every request.

-- BAD: the client picks the amount
RegisterNetEvent('myshop:sell', function(amount)
    local Player = QBCore.Functions.GetPlayer(source)
    Player.Functions.AddMoney('cash', amount)  -- exploitable
end)

-- GOOD: the server decides
RegisterNetEvent('myshop:sell', function(itemName)
    local Player = QBCore.Functions.GetPlayer(source)
    if not Player then return end

    local price = Config.Prices[itemName]
    if not price then return end
    if not Player.Functions.RemoveItem(itemName, 1) then return end

    Player.Functions.AddMoney('cash', price, 'shop-sale')
end)

Our client vs server guide covers this split in depth. It is the concept most worth understanding early.

Player metadata: QBCore's standout feature

One thing QBCore does particularly well is metadata โ€” flexible per-player data like hunger, thirst, stress and licences.

-- read
local stress = Player.PlayerData.metadata['stress']

-- write
Player.Functions.SetMetaData('stress', 50)

Want "player has a fishing licence" or "player's stress level"? Add a metadata key. No schema change, no migration. This is a big reason developers enjoy writing QBCore scripts, and it is where a lot of a server's personality ends up living.

How data is stored

QBCore stores player and server data in a MySQL/MariaDB database, accessed through oxmysql. When a player logs in, their character loads from the database; when they log out or the server saves, it writes back.

Understanding that a database sits behind your server matters โ€” a large share of setup problems are connection problems, not script problems. Our oxmysql troubleshooting guide covers the usual causes.

QBCore, QBox and the ecosystem

You will also see QBox mentioned. It is a community continuation of the QBCore codebase, and scripts written for QBCore generally work on it. If you see a script listing "QBCore / QBox" support, that is why.

Around the framework sits the ox stack โ€” ox_lib, ox_inventory, ox_target โ€” which most modern QBCore servers run alongside qb-core. See the ox stack overview for how the pieces fit.

Getting started with QBCore

A rough path for a beginner:

  1. Set up a FiveM server using txAdmin, which can deploy a QBCore template automatically โ€” by far the easiest start. Our txAdmin setup guide walks through it.
  2. Make sure your database (MySQL/MariaDB) is connected.
  3. Confirm the base server boots and you can join.
  4. Add resources one at a time, checking each works before adding the next.
  5. Configure jobs, money and items to fit your server's vision.

That fourth point matters more than it sounds. Adding twenty scripts at once and then trying to work out why the server will not start is a miserable way to learn โ€” and finding a script conflict is far easier when you changed one thing.

Common beginner mistakes

  • Wrong load order. qb-core must come first.
  • Trusting the client. Every value sent from a client is attacker-controlled.
  • Editing `qb-core` directly. Your changes vanish on the next update. Use exports and events instead.
  • Skipping the `if not Player then return end` check. Silent nil errors under load.
  • Installing everything at once. You will not know what broke.

QBCore vs ESX

If you're choosing between them, we have a full balanced comparison here. The short version: QBCore includes more out of the box and has strong current momentum, while ESX has a longer track record and the largest script library. Both are solid โ€” and on the ESX side, make sure it is ESX Legacy rather than an old build.

Adding scripts to your QBCore server

Once your QBCore base is running, you'll want resources that fit cleanly. Look for scripts that are built for QBCore (or dual-framework), validated server-side, and well optimised. Our guide on spotting optimised versus bloated scripts covers what to check before installing.

At Viper Development, every script supports QBCore with automatic framework detection โ€” so it drops into your QBCore server and works, with an open config so you can tune it. Browse our QBCore-compatible scripts โ†’

Premium FiveM scripts for QBCore & ESX

Viper Development builds escrow-protected, dual-framework scripts that install clean and run without dragging your server down.

Keep reading

Related guides