Your first BS19 resource
This guide builds a small resource from nothing: a /checkin command that gives a survivor one water bottle, at most once an hour. It takes about 15 minutes. You need a running BS19 server, access to its files and the txAdmin console, and a text editor (VS Code works well).
When it works, Writing a resource on top of bs_core shows the next steps: client code, callbacks and the traps to avoid.
1. Create the folder
Section titled “1. Create the folder”In your server’s resources folder, create a folder called [local] (the brackets matter, they make it a category, not a resource) and inside it a folder called bs_checkin. Keep your own resources in [local] so framework updates never overwrite them.
resources/[local]/bs_checkin/├── fxmanifest.lua├── config.lua└── server.luaThe folder name is the resource name. Start it with bs_ so it can’t clash with another script.
2. fxmanifest.lua
Section titled “2. fxmanifest.lua”Every FiveM resource needs this file. It tells the server which files to load and on which side.
fx_version 'cerulean'game 'gta5'lua54 'yes'
name 'bs_checkin'description 'My first BS19 resource'
shared_scripts { '@bs_core/shared/sh_bridge.lua', -- gives you BSB (commands, callbacks) 'config.lua',}server_scripts { 'server.lua' }
dependencies { 'bs_core', 'bs_inventory' }The @bs_core/shared/sh_bridge.lua line loads the BS19 bridge into your resource. Without it, BSB does not exist and the server file fails.
3. config.lua
Section titled “3. config.lua”Put every value a server owner might want to change in one table, so nobody has to edit your code.
Checkin = { item = 'water_bottle', -- any item name from bs_inventory's item list amount = 1, cooldown = 3600, -- seconds between two check-ins (1 hour)}4. server.lua
Section titled “4. server.lua”local lastCheckin = {} -- [charId] = os.time() of the last check-in
local function notify(src, kind, message) TriggerClientEvent('bs:ui:notify', src, { type = kind, message = message })end
BSB.RegisterCommand('checkin', nil, 'Daily survivor check-in', {}, function(src) if src == 0 then return print('Run /checkin in game, not in the console.') end
local p = exports.bs_core:GetPlayerSummary(src) if not p then return notify(src, 'error', 'Pick a character first.') end
local now = os.time() local last = lastCheckin[p.charId] if last and now - last < Checkin.cooldown then local minutes = math.ceil((Checkin.cooldown - (now - last)) / 60) return notify(src, 'error', ('Come back in %d min.'):format(minutes)) end
local ok, reason = exports.bs_inventory:GiveItem(src, Checkin.item, Checkin.amount) if not ok then return notify(src, 'error', 'No room: ' .. tostring(reason)) end
lastCheckin[p.charId] = now notify(src, 'success', ('Welcome back, %s. Here is some water.'):format(p.firstName))end)What it does, line by line:
BSB.RegisterCommandcreates the chat command. Thenilmeans everyone can use it; put an ACE like'bs.admin'there to limit it to staff.GetPlayerSummaryreturnsnilwhile the player is still on the character screen, so check it before anything else.- The cooldown is stored per character (
charId), not per player, so a second character gets its own check-in. It resets when the resource restarts, which is fine for a first resource. - Items always go through
exports.bs_inventory:GiveItem. It returnsfalseand a reason when the inventory is full. Never write to the database yourself.
5. Start it
Section titled “5. Start it”Add this line at the end of server.cfg, after the BS19 resources:
ensure bs_checkinThen, in the txAdmin live console (no server restart needed):
refreshensure bs_checkinrefresh makes the server notice the new folder. The console should print Started resource bs_checkin. After you edit a file later, ensure bs_checkin alone reloads it.
6. Test it in game
Section titled “6. Test it in game”- Join the server and pick a character.
- Press T, type
/checkinand press Enter. You get a green notification and a water bottle in your inventory (I). - Type
/checkinagain. You get a red “Come back in 60 min.” message.
If it doesn’t work
Section titled “If it doesn’t work”| What you see | Why | Fix |
|---|---|---|
Couldn't find resource bs_checkin | The server hasn’t seen the folder, or the name differs | Run refresh, check the folder is named exactly bs_checkin |
attempt to index a nil value (global 'BSB') | The bridge line is missing | Check the @bs_core/shared/sh_bridge.lua line in fxmanifest.lua |
No such export GetPlayerSummary | bs_core isn’t started yet | Keep ensure bs_checkin below the BS19 resources in server.cfg |
/checkin does nothing, no error | You’re still on the character screen, or the command was never registered | Pick a character, then look at the console for a red [bs_checkin] line |
| “No room: …” | Your inventory is full or too heavy | Drop something and try again |
Any red error in the console also names the file and line. Fix it, run ensure bs_checkin again, and retry.
Ideas to try next
Section titled “Ideas to try next”- Change
itemtobandageinconfig.luaand runensure bs_checkin. No code change needed. - Give some cash as well:
exports.bs_core:AddMoney(src, 'cash', 25, 'checkin'). - Give XP:
exports.bs_core:AddXP(src, 10, 'checkin'). - Browse the calls you can use in Exports & events.
bs19.org · Privacy · Terms · Cookie settings
Cookies and outside content
The site only needs two essential cookies to keep you logged in and protect forms. Videos and streams from YouTube and Twitch load from their servers, which can set their own cookies, so they stay off until you say yes. Nothing is pre-ticked and you can change your mind any time with "Cookie settings" at the bottom of every page. Details.
Questions about the server, the framework or the site? A real person reads this, usually within a day.