FiveM & QBCore · Practical guide

How to Add a Fishing Job to Your QBCore FiveM Server

A fishing job is one of the most popular civilian activities on FiveM. This guide covers setting up a complete QBCore fishing system with different spots, fish types and selling.

Stellar AI · Updated 8 September 2026 · 7 min read

A practical guide to how to add a fishing job to your qbcore fivem server, with implementation decisions, validation steps, and security considerations for a production-minded project.

Overview

Adding a robust fishing job to a QBCore FiveM server means more than drawing bait and spawning fish. You need a clear architecture split between client visuals and server authority, secure server-side validation for rewards and inventory changes, a clean resource layout, and a plan for testing, deployment, and maintenance. This guide walks through architecture choices, concrete implementation patterns, security considerations (never trust client input), integration options (ox_lib, ox_inventory, ESX equivalents), and practical deployment steps.

Architecture and responsibilities

Design the fishing job as a modular resource that separates responsibilities:

  • Client: UI, animations, local minigame, input and camera effects, hit detection for local visuals. The client may request actions but does not grant rewards directly.
  • Server: authoritative checks, issuing items/money, storing sessions/tokens, database writes (selling, processing), cooldowns and rate-limits, anti-cheat decisions.
  • Database: fish tables for prices, player job state (if persistent), migration scripts for items and job records.
  • Optional integration: ox_lib for menus, ox_inventory for item handling or QBCore inventory API, reusable job entries in qb-core shared files if you want job appearing in job lists.

Resource structure and fxmanifest

A clear file layout keeps the resource maintainable. Example minimal layout:

qb-fishing/
  fxmanifest.lua
  client/
    main.lua
    ui.lua
  server/
    main.lua
    handlers.lua
  config.lua
  sql/
    migrations.sql

Example fxmanifest snippet:

fx_version 'cerulean'
game 'gta5'

author 'YourName'
description 'QBCore fishing job'
version '1.0.0'

shared_script 'config.lua'
client_scripts {
  'client/main.lua',
  'client/ui.lua'
}
server_scripts {
  '@oxmysql/lib/MySQL.lua', -- if using oxmysql
  'server/main.lua',
  'server/handlers.lua'
}

Server validation, tokens and security

Never trust client-provided coordinates, counts, or timestamps. A reliable pattern is a short-lived server-issued token that authorizes a fishing session. This prevents clients from spoofing remote actions because only the server knows valid tokens and expiration times.

Pattern:

  1. Client enters fishing zone and sends a request to start a session: TriggerServerEvent('qb-fishing:server:requestSession', zoneId).
  2. Server checks job permissions, cooldowns, and optionally that the player is allowed to fish now. If OK, server generates a token and stores it in memory keyed by source with an expiration timestamp.
  3. Client can request catches using the token: TriggerServerEvent('qb-fishing:server:attemptCatch', token).
  4. Server validates the token and expiration server-side. Only after validation does the server add items/money to the player and optionally update database records.

This pattern avoids trusting any client-submitted coordinates and centralizes reward decisions on the server. Implement rate-limiting and anti-spam checks (per-minute catch caps) and log suspicious behavior for monitoring.

Server-side token example (Lua)

local QBCore = exports['qb-core']:GetCoreObject()
local sessions = {} -- [source] = {token=xxxx, expires=os.time()+60}

RegisterNetEvent('qb-fishing:server:requestSession', function(zoneId)
  local src = source
  local Player = QBCore.Functions.GetPlayer(src)
  if not Player then return end
  -- Permission checks
  if Player.PlayerData.job.name == 'police' then return end -- example
  local token = tostring(math.random(100000,999999))
  sessions[src] = { token = token, expires = os.time() + 60, zone = zoneId }
  TriggerClientEvent('qb-fishing:client:sessionStarted', src, token)
end)

RegisterNetEvent('qb-fishing:server:attemptCatch', function(token)
  local src = source
  local Player = QBCore.Functions.GetPlayer(src)
  local s = sessions[src]
  if not s or s.token ~= token or os.time() > s.expires then
    -- invalid or expired
    TriggerClientEvent('qb-fishing:client:sessionDenied', src)
    return
  end
  -- Rate limiting example
  if Player.PlayerData.metadata.fishCooldown and (os.time() - Player.PlayerData.metadata.fishCooldown) < 2 then
    return
  end
  Player.Functions.AddItem('fish_small', 1)
  Player.Functions.RemoveMoney('cash', 5) -- example processing cost or fees if required
  Player.Functions.UpdateMetaData('fishCooldown', os.time())
end)

Item economy, processing and DB schema

Decide whether fish are raw items that need processing or direct sell items. Example flow:

  • Catch raw fish (items: fish_small, fish_medium, fish_large).
  • Take to processing location to transform raw fish to filet or canned goods (server processes inventory changes).
  • Sell processed goods at a vendor NPC or sellpoint. Transactions occur server-side.

SQL migration sample (for oxmysql/ghmattimysql):

-- sql/migrations.sql
INSERT INTO items (name, label, weight, rare, usable, description) VALUES
('fish_small', 'Small Fish', 200, 0, 0, 'A small fish.'),
('fish_medium', 'Medium Fish', 350, 0, 0, 'A medium fish.'),
('fish_large', 'Large Fish', 600, 1, 0, 'A large fish.');

Implementation choices: minigames, animations, and integrations

Choices to match playstyle:

  • Minigame: Simple timed progress bar (client) vs skill-based minigame (mini-UI). Keep minigame on client for smooth UX but require a server-issued session token to accept rewards.
  • Inventory: Use QBCore.Functions for default inventory operations. If using ox_inventory, adapt AddItem/RemoveItem calls to that API. Do all item granting on server.
  • Context menus and interaction: ox_lib context menus provide polished interaction points for starting/stopping job actions and selling. They are client components only for UI—authorization still runs server-side.
  • Animations and synchronisation: Trigger local animations for visual feedback. Avoid synchronizing server position; let client animate, and validate actions via token-checks and cooldowns.

Code patterns: robust server handlers

Keep server code modular and maintain authority. Use dedicated handler functions, centralize economy changes, and emit logs on important operations:

local function giveFish(player, fishType, amount)
  -- additional validations: inventory space, daily caps, etc.
  player.Functions.AddItem(fishType, amount)
  -- log in server logs for audits
  print(('[fishing] %s received %s x%d'):format(player.PlayerData.citizenid, fishType, amount))
end

-- call giveFish after token validation (see previous token snippet)

Testing and QA

Testing should cover edge cases where clients try to bypass flows. Use these steps:

  1. Unit test server handlers locally with multiple simulated sources to check session expiration and cleanup.
  2. Playtest with two-player scenarios: one normal, one attempting to spam catch events to verify rate-limits and anti-cheat triggers.
  3. Test DB migrations on a staging server with a backup plan for rolling back in production.
  4. Verify inventory boundaries: item stacking, weight caps, and sellpoint behavior with zero inventory cases.
  5. Simulate missing dependencies (oxmysql down, inventory unavailable) and confirm the server handles failures gracefully and sends descriptive errors to admins/logs.

Deployment and maintenance

Deployment checklist:

StepWhatResponsible
Install resourcePlace qb-fishing in resources, add start qb-fishing to server.cfgDev/Ops
Run migrationsApply sql/migrations.sql using your DB tool (oxmysql/ghmattimysql)DB Admin
ConfigureEdit config.lua for zones, prices, job namesDeveloper
MonitorCheck logs for token errors, failed DB calls, and suspicious activityOps

Use a deployment or monitoring tool to track resource health. If you use a managed platform for resource deployment and logs, integrate server logs and alerts. For continuous improvement, keep configuration separated from code and use feature flags to enable/disable new game mechanics without redeploying code.

Stellar AI can help generate and revise the project files for this workflow. Describe your framework, existing dependencies, and one testable feature, then bring back errors for a focused revision. You remain responsible for running the tests and managing deployment in your own development environment.

Maintenance: versioning, backups, and cleanup

Maintenance tasks include:

  • Keep resource versioned and tag releases. Document config changes.
  • Back up databases before applying migrations or changing item definitions.
  • Add server-side garbage collection for expired tokens/sessions. Example: periodic loop that clears sessions table and writes audit logs.
  • Rotate logs and keep an incident response plan in place for exploits or item dupes.
  • Periodically review and update permissions for jobs and salary settings in qb-core shared definitions to align with economy balance.

If you want a hosted interface for deployments and rapid rollback capabilities consider integrating your deployment pipeline with staging and production rollouts; you can connect and monitor via a platform such as https://trystellarai.com/app for centralized operations.

Roblox/Luau considerations (if cross-platform inspiration)

If you adapt patterns for Roblox: always treat the server as authoritative. Use RemoteEvents/RemoteFunctions only to request actions; have the server validate RemoteEvent calls and handle DataStore writes with retry/backoff and failure handling. Avoid putting any item granting logic on the client. Implement server-side cooldowns and store session state on the server. Handle DataStore failures by queuing and retrying writes and informing players of transient issues.

Checklist: minimum requirements before launch

  • Server-side session token system implemented and tested.
  • Rate limits and cooldowns on catches to prevent rapid farming.
  • Inventory operations only on server: AddItem/RemoveItem controlled by server handlers.
  • SQL migrations applied and tested on staging.
  • Error handling for DB downtime and graceful failures.
  • Logging for suspicious behavior and audit trails for item grants.
  • Deployment plan with rollback and backups.
  • Automated cleanup of expired sessions and stale data.

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 →