DocumentationMigrationESX to QBCore Migration

ESX to QBCore Migration Guide

Switching from ESX to QBCore opens the door to modern APIs, modular resources, and an active development community. This guide outlines a staged approach so you can migrate safely without losing player data or custom gameplay systems.

Why teams migrate

  • Modern architecture – shared callbacks, metadata, and better exports
  • Active ecosystem – maintained default jobs and utilities
  • Security-focused – built-in safeguards against common exploits
  • Extensible – Lua modules, UI patterns, and community tooling

Pre-migration checklist

  • Dedicated staging server mirroring production hardware
  • Full backup of ESX resources and MySQL database
  • Inventory of custom scripts and dependencies
  • Freeze on new feature deployments during migration window
  • Communication plan for staff and players
⚠️

Never migrate directly on a live server. Always validate the process on a staging environment and keep a rollback path ready.

Framework concept mapping

ESX ConceptQBCore EquivalentNotes
xPlayer objectQBCore.Functions.GetPlayer()Metadata stored in PlayerData
Accounts (bank, money)Money accounts (cash, bank)Access via Player.Functions.GetMoney(type)
Job grades (job.grade_name)PlayerData.job.grade.nameSupports duty toggle and permissions
ESX events (esx:*)QBCore events (QBCore:*)Many renamed and namespaced
Items (esx_addoninventory)qb-core/shared/items.luaUses metadata for variants
DatastorePlayer metadata / global statesConvert JSON blobs

Phase 1 – Prepare QBCore baseline

  1. Clone the latest QBCore repository into resources/[qb]/qb-core
  2. Install essential resources (qb-inventory, qb-clothing, qb-phone, etc.)
  3. Configure server.cfg with QBCore load order (core → dependencies → jobs)
  4. Import the default QBCore SQL schema into a new database (e.g., qbcore_migration)
  5. Copy custom assets (vehicles, props) that will remain in use

Phase 2 – Migrate player data

1. Create staging tables

CREATE TABLE qbcore_players LIKE qbcore.players;
ALTER TABLE qbcore_players ADD COLUMN esx_identifier VARCHAR(60);

2. Transform ESX player rows

INSERT INTO qbcore_players (citizenid, license, name, money, job, gang, position, metadata, esx_identifier)
SELECT
    LOWER(HEX(UUID_TO_BIN(UUID()))) AS citizenid,
    REPLACE(identifier, 'steam:', '') AS license,
    CONCAT(firstname, ' ', lastname) AS name,
    JSON_OBJECT('cash', money, 'bank', bank) AS money,
    JSON_OBJECT('name', job, 'grade', job_grade) AS job,
    JSON_OBJECT('name', 'none', 'grade', 0) AS gang,
    JSON_OBJECT('x', position_x, 'y', position_y, 'z', position_z) AS position,
    JSON_OBJECT('lastplayed', last_login, 'phone', phone_number) AS metadata,
    identifier AS esx_identifier
FROM es_extended.users;

3. Migrate owned items

INSERT INTO players_inventory (citizenid, items)
SELECT
    p.citizenid,
    JSON_ARRAYAGG(JSON_OBJECT('name', i.item, 'amount', i.count, 'metadata', JSON_OBJECT()))
FROM esx_addoninventory.items i
JOIN qbcore_players p ON p.esx_identifier = i.owner
GROUP BY p.citizenid;

Review data manually—ensure money balances, job grades, and inventory counts look correct.

Phase 3 – Convert resources

  1. Replace ESX shared utilities with QBCore equivalents (QBCore.Shared, QBCore.Functions)
  2. Update event names using the mapping table below
  3. Rewrite server callbacks to use QBCore.Functions.CreateCallback
  4. Replace ESX menu/NUI implementations with QBCore UI helpers where possible
  5. Adjust permissions to use QBCore job grades or metadata flags

Event mapping quick reference

ESX EventQBCore Replacement
esx:getSharedObjectexports['qb-core']:GetCoreObject()
esx:playerLoadedQBCore:Server:OnPlayerLoaded
esx:playerDroppedQBCore:Server:OnPlayerUnload
esx:addInventoryItemPlayer.Functions.AddItem
esx:removeInventoryItemPlayer.Functions.RemoveItem
TriggerEvent('esx:getSharedObject', cb)local QBCore = exports['qb-core']:GetCoreObject()

Example conversion

-- ESX
ESX.RegisterServerCallback('myresource:getPlayer', function(source, cb)
    local xPlayer = ESX.GetPlayerFromId(source)
    cb(xPlayer.getIdentifier())
end)
 
-- QBCore
QBCore.Functions.CreateCallback('myresource:getPlayer', function(source, cb)
    local Player = QBCore.Functions.GetPlayer(source)
    cb(Player and Player.PlayerData.citizenid)
end)

Phase 4 – Functional testing

  • Use Resmon Basics to profile the staging server
  • Verify money, inventory, job changes, and metadata updates in-game
  • Run through mission-critical scripts (police, EMS, economy)
  • Invite staff for scenario-based testing (robberies, crafting, housing)

Document any missing features and decide whether to recreate them in QBCore or retain legacy ESX components temporarily.

Phase 5 – Production rollout

  1. Schedule downtime and notify players
  2. Backup ESX production database immediately before maintenance
  3. Restore the validated QBCore database backup
  4. Deploy converted resources and verify load order
  5. Monitor logs, resmon, and error reports closely for the first 48 hours

Post-migration tasks

  • Update onboarding guides and staff documentation
  • Train developers on QBCore-specific patterns like Safe Server Events
  • Track feedback via Discord/forums and adjust configs quickly
  • Plan incremental enhancements now that QBCore is live

Celebrate once the migration is stable—but keep a retrospective log so future upgrades (like QBCore v1 → v2) are even smoother.