FiveM & QBCore · Practical guide

FiveM Heist Scripts — Everything You Need to Know

A guide to every type of heist script for FiveM — bank vaults, jewellery stores, house robberies and more. How to set each one up and balance the rewards.

Stellar AI · Updated 8 September 2026 · 6 min read

A practical guide to fivem heist scripts — everything you need to know, with implementation decisions, validation steps, and security considerations for a production-minded project.

Overview

This guide explains how to design, build, secure, test, deploy, and maintain heist scripts for FiveM servers (QBCore / ESX / ox_lib) and provides parallel guidance for Roblox (Luau) implementations. It focuses on architecture, server validation, data integrity, concurrency control, and safe client-server communication patterns. If you manage server tooling or want integrated analytics during development, consider using the Stellar AI deployment app for staging and monitoring: Stellar AI App.

Architecture and core responsibilities

Design a heist as a set of independent sub-systems with clear responsibilities. Typical components:

  • Server authority layer: Enforces all game rules (money rewards, item transfers, cooldowns, job checks). Never trust client-sent state — treat it as a request only.
  • Persistence layer: Database access for inventories, accounts, heist state, and logs. Use prepared queries and transactions for multi-step operations.
  • Sync / event layer: Broadcast state changes to clients using server-controlled events.
  • Anti-abuse layer: Rate limiting, event throttles, and validation to prevent exploitation.
  • Telemetry and logging: Store detailed audit logs of heist attempts and critical actions.

Separating concerns helps you reason about security boundaries and makes testing and deployments more predictable.

Server validation and security best practices (FiveM)

For FiveM implementations, assume all client messages are untrusted. The server must verify every action before applying game-state changes. Specific measures:

  • Validate player job/role and inventory on the server before granting access to heist start triggers or rewards.
  • Use server-side cooldowns stored in memory or DB so clients cannot repeatedly attempt state changes.
  • Sanitize and validate any numeric values (amounts, durations) on the server; don't accept client-specified reward multipliers.
  • Keep critical checks inside RegisterNetEvent callbacks on the server and call source identifiers (player IDs) only from server context.

Example server-side pattern (Lua):

RegisterNetEvent('heist:attempt')
AddEventHandler('heist:attempt', function(payload)
  local src = source
  local user = QBCore.Functions.GetPlayer(src)
  if not user then return end
  -- Server-validated checks
  if not user.PlayerData.job or user.PlayerData.job.name ~= 'criminal' then
    return TriggerClientEvent('heist:denied', src)
  end
  if CooldownManager:isOnCooldown(user.PlayerData.citizenid) then
    return TriggerClientEvent('heist:denied', src, 'cooldown')
  end
  -- Proceed with DB-backed transaction, audit, etc.
end)

Roblox-specific server authority and DataStore handling

Roblox requires strict server-authoritative design: RemoteEvents and RemoteFunctions should carry minimal data from client to server (intent + identifiers). The server must validate player state (leaderstats, roles, inventory) before committing reward changes. Always make DataStore operations robust to failure:

  • Wrap DataStore operations with pcall and exponential backoff retries.
  • Use optimistic concurrency with version tokens where possible or implement per-player locking to prevent race conditions.
  • Gracefully degrade when DataStore is unavailable: queue local state in MemoryStore or in a server-side cache, informing players of delays instead of silently failing.

Example Luau snippet for a RemoteEvent handler:

local Remotes = game:GetService("ReplicatedStorage"):WaitForChild("Remotes")
local DataStoreService = game:GetService("DataStoreService")
local PlayerStore = DataStoreService:GetDataStore("PlayerData")

Remotes.HeistStart.OnServerEvent:Connect(function(player, heistId)
  -- Minimal client input: only heistId, server checks everything else
  if not ValidatePlayerForHeist(player, heistId) then
    Remotes.HeistResponse:FireClient(player, false, "invalid")
    return
  end
  local success, result = pcall(function()
    return PlayerStore:GetAsync(player.UserId)
  end)
  if not success then
    Remotes.HeistResponse:FireClient(player, false, "datastore_error")
    return
  end
  -- Proceed with server-authoritative mutations
end)

Integration with QBCore / ESX / ox_lib

Hook into your server framework for consistent player objects and utility functions. Recommendations:

  • QBCore: use QBCore.Functions.GetPlayer and exports for inventory/money operations. Wrap changes in a single server-side function for the atomic heist reward transaction.
  • ESX: use server callbacks and shared items APIs. Be mindful of older ESX versions that do synchronous DB calls; prefer async-compatible forks.
  • ox_lib: take advantage of common utilities like notifications, busy flags, and progress bars, but keep the authoritative logic on the server exports.

When using these frameworks, create a heist module that abstracts framework-specific calls to allow future refactors or multiple-framework support.

Database patterns and transactions

Heists often update several tables: player accounts, inventories, logs, and global heist state. Use transactions to maintain consistency:

  • When applying rewards, deduct items before crediting money, and roll back if any step fails.
  • Use row-level locks or application-level locking for multi-player heists to avoid double-claiming the same loot.
  • Prefer parameterized queries with a mature connector (ghmattimysql, mysql-async, or equivalent) to avoid injection and ensure performance.

If your DB doesn't support multi-statement transactions easily, implement application-level compensating transactions and ensure idempotency keys for retries.

Concurrency, anti-cheat, and denial mitigation

Attacks you'll see: repeated event spam, spoofed state changes, or simultaneous claims. Defenses:

  • Rate limit critical server events per-player and per-target (e.g., per-robbery point).
  • Use atomic server-side checks that simultaneously verify and mutate state (check-then-set within one DB transaction or memory lock).
  • Log suspicious patterns (rapid repeated attempts, impossible timings) and auto-ban or flag for manual review.
  • Implement sanity checks on timing and positions — but derive all authoritative positions from server-sent references when required.

Testing and QA workflow

A robust testing pipeline prevents regressions and security holes.

  • Unit tests for server-side modules: validation logic, reward calculations, and cooldown managers. Use mocks for DB and framework APIs.
  • Integration tests on a local FiveM server: simulate multiple players, network latency, and concurrent heist starts.
  • Roblox: use local server tests in Studio with simulated RemoteEvents and DataStore stubs. Test pcall failure paths and queue behavior.
  • Fuzz test event inputs from clients to ensure server never accepts malformed or out-of-range data.
  • Load-test the DB paths for heist success/failure to ensure your persistence layer scales.

Example test checklist (condensed)

AreaTestExpected result
Server validationClient sends start request without jobServer denies and logs attempt
DB transactionSimulate DB failure mid-transactionRollback; player notified; log recorded
ConcurrencyTwo players claim same lootOnly one succeeds; other gets refund/denied
DataStoreDataStore pcall failureRetry/backoff; queue; inform player
ExploitRapid event spamRate limit enforced; suspicious log entry

Deployment and maintenance

Follow an automated and monitored deployment approach:

  • Package resources with a consistent fxmanifest.lua and version tags. Keep migrations as SQL scripts or scripted state transitions for each release.
  • Deploy to a staging server first and run smoke tests that simulate heist flows.
  • Automate backups for critical DB tables and the heist logs before applying migrations.
  • Use runtime monitoring and alerts on error rates, pcall failures (Roblox), and DB transaction errors.
  • Maintain a small patch window for emergency hotfixes; ship safeguards that can be toggled server-side to disable heist features if needed.

For operational tooling and staging environments, teams often use hosted platforms to manage deployments and observability. You can integrate an app-based workflow for deployments and monitoring via the Stellar AI deployment app: Stellar AI App.

Maintenance: logging, audit, and player transparency

Keep high-fidelity logs for each heist attempt including:

  • Player identifiers, timestamps, actions taken, and server-side decisions.
  • DB transaction outcomes and any rollbacks.
  • Rate-limit and anti-cheat triggers.

Provide transparent in-game messages when operations fail (DataStore errors, server maintenance) so players understand delays and do not attempt to retry unsafely.

Practical checklist before going live

  1. All client inputs are validated on the server and treated as requests only.
  2. Critical state changes are performed under DB transactions or atomic server locks.
  3. Rate limiting and anti-spam logic in place for every exposed event.
  4. DataStore operations wrapped with pcall and retry/backoff.
  5. Audit logs centralised and backups scheduled.
  6. Staging environment with smoke tests that cover heist success and failure paths.
  7. Rollback and feature-disable mechanisms ready for hotfixes.

Build your next system with Stellar AI

Describe one feature, get organized project files, then bring back your errors to keep improving. Start free with no card required. Test generated code in a private development environment before release.

Create your first script free →