RB
RB Studios
DocsScriptsSubscriptionsToolsBlog
RB
RB Studios

Premium FiveM scripts engineered for serious servers. Made by a tiny team that ships.

Product
  • Scripts
  • Subscriptions
  • Tools
  • Roadmap
  • Changelog
Developers
  • Docs
  • GitHub
Studio
  • Team
  • Blog
  • About
© 2026 RB Studios·Not affiliated with Rockstar Games or Cfx.re
All systems operational·build 1.0.0-rc.4
BlogEcosystemMigrating from QBCore to QBox without downtime.
EcosystemFeb 09, 2026·3 min read

Migrating from QBCore to QBox without downtime.

A field guide to the upgrade path: schema diffs, the bridge layer, and the four edge cases that will bite you on go-live night.

RB
Reid Bennett
RB Studios

We've now done four QBCore → QBox migrations in production, including one for a 200-slot server with twenty-thousand persisted vehicles. Every one of them surfaced an edge case the migration guides don't mention. This post is the field guide we wish we'd had on the first one.

The high-level path

The migration itself is conceptually simple:

  1. Add the QBox core resource alongside QBCore.
  2. Run the QBox migration scripts against your existing database.
  3. Swap the bridge layer your scripts use to talk to the framework.
  4. Cut over at a maintenance window. Smoke-test. Done.

Each of those steps has at least one foot-gun. The goal of this post is to point them out before they bite.

Step 1: schema diffs you'll actually see

QBox is mostly a superset of QBCore's schema, but "mostly" is the word doing all the work. The columns that have changed shape in production for us:

  • players.charinfo — JSON shape gains a gender enum field. QBCore servers that stored gender as m / f need to migrate to male / female. A one-line UPDATE query, but if you miss it, character creation will reject every existing player.
  • player_vehicles.mods — the tyreSmokeColor field moves from a flat array to an object. The compat shim handles reads but not writes; vehicle saves silently lose tyre smoke until you migrate.
  • bans — discord and license identifiers now live in a normalized identifiers JSON column. The compat view papers over reads.
-- the migration we run before the cutover
UPDATE players
   SET charinfo = JSON_SET(
     charinfo,
     '$.gender',
     CASE JSON_EXTRACT(charinfo, '$.gender')
       WHEN '"m"' THEN 'male'
       WHEN '"f"' THEN 'female'
       ELSE JSON_EXTRACT(charinfo, '$.gender')
     END
   )
 WHERE JSON_EXTRACT(charinfo, '$.gender') IN ('"m"', '"f"');

Run this before the framework swap, while QBCore is still authoritative. It's idempotent.

Step 2: the bridge layer

Every RB Studios script ships with a bridge — a thin adapter between our internal API and whatever framework you're running. The bridge for QBCore and the bridge for QBox are deliberately separate files, not branches inside one file. This means the cutover is a config flip, not a code change.

-- before
Config.framework = "qbcore"

-- after
Config.framework = "qbox"

If you've been editing our bridge directly (please don't), this is the moment your edits become invisible. Move customizations to the Config.hooks table — it survives bridge swaps.

Step 3: the four edge cases

These are the ones that will bite you on go-live night. We've now hit each of them at least twice.

1. State bags vs. metadata

QBox prefers state bags for player metadata; QBCore prefers a PlayerData.metadata object. If you have third-party scripts reading PlayerData.metadata.<thing>, they'll silently stop seeing updates the moment QBox is authoritative.

The fix is a one-line bridge in QBox that mirrors state-bag changes back into the PlayerData object. We ship this by default; most other resources don't. Audit your third-party scripts for PlayerData.metadata reads before the cutover.

2. Job grades as strings

QBCore stored job grades as integers. QBox stores them as strings. If any of your scripts compare grades with == and a number literal, they will silently fail closed and tell your mechanics they're not on duty.

3. The vehicle key event

QBCore fires qb-vehiclekeys:client:SetOwner. QBox fires qbx_vehiclekeys:client:setOwner. Different namespace, different casing. The compat shim aliases one to the other for the lifetime of a single boot — if you restart qbx_vehiclekeys mid-session, the alias is gone until the next full server restart.

4. Bans take effect on next connect, not now

QBCore's ban check runs on every player tick. QBox's runs on playerConnecting. This is the right behavior — way cheaper — but it means a ban issued mid-session doesn't kick the player until they reconnect. If your admins are used to instant-kick-on-ban, give them a heads-up.

What "no downtime" actually means

Strictly speaking, there is a downtime: the moment you ensure qbx_core and restart the framework, every active player is dropped. What we mean by no-downtime is that the migration itself doesn't require a long maintenance window — a single thirty-second framework restart is enough, and the database work happens online.

For the 200-slot server, the actual visible downtime was forty-one seconds. Players reconnected, characters loaded, and the migration was done before the support queue caught up.

When to migrate

We're now recommending QBox for any new server. For existing QBCore servers: if you're stable and your players are happy, the migration is optional. The performance and ergonomic improvements are real, but they're not "drop everything" real.

If you do migrate, run the database migrations on a staging clone first. There is no substitute. The schemas you'll find in your production database are almost never exactly what the migration scripts expect — every server has its own history of half-finished schema changes from old resources. Find them on staging, not at 2am on cutover night.

Thanks for reading. Catch us in Discord if you want to talk shop.
All posts
More from the studio

Keep reading

All posts

Ship log — March 2026.

Six releases, two new scripts, and the first public look at rb-housing. Plus the bug we held back from v1.4.2 and why.

RS
RB Studios
Apr 02, 2026

Obfuscation isn't security — and what we do instead.

We get the question every release: why aren't your scripts open source? Here's how we actually protect server stability without leaking attack surface.

RB
Reid Bennett
Mar 18, 2026

Engineering for a 0.02ms idle budget.

How rb-mechanic stays under 0.02ms idle on a 64-slot server — event batching, cache hierarchies, and the threads we never spin up.

MH
Mira Hoang
Feb 27, 2026