A production-ready PocketBase instance in one FiveM resource with automatic setup, realtime events, backups, SQL queries, transactions, and comprehensive exports.
- Download and extract to your
resourcesfolder - The resource folder name should be
pb - Add
ensure pbto yourserver.cfg - Start your server
That's it! PocketBase will automatically:
- Start on
127.0.0.1:8090 - Create a superuser account
- Authenticate your scripts
- Work immediately with zero configuration
By default, the admin UI is not exposed (most secure). Your scripts can still access PocketBase.
To enable public admin UI access:
Config.ExposeAdmin = true -- Set to true in config.luaWhen enabled, configure your public URL:
Config.Host = "" -- Leave empty to auto-detect, or set to your IP/domain
Config.Port = 8090Important: If you enable ExposeAdmin, you must:
- Open port 8090 in your firewall
- Configure port forwarding if needed
- Set a strong superuser password
Credentials are auto-generated on first startup. Find them in config.lua:
Config.Superuser = {
Email = "admin@localhost.local", -- Auto-generated
Password = "qOl9dbdZHF54ixFfM9th", -- Auto-generated (20 char random)
}Security: These credentials are stored in plain text. Protect your config.lua file!
Enable automatic database backups:
Config.Backup = {
Enabled = true, -- Enable backup system
OnStartup = true, -- Backup before each startup (recommended)
Schedule = 86400, -- Auto-backup every 24 hours (0 = disabled)
KeepLast = 7, -- Keep last 7 backups, delete older
BackupPrefix = "auto_",
}Backups are stored in the pb_data/backups directory.
Configure email sending for password resets, verifications, etc:
Config.Advanced = {
SMTP = {
Enabled = true,
Host = "smtp.gmail.com",
Port = 587,
Username = "your-email@gmail.com",
Password = "your-app-password",
TLS = true,
},
}Offload file uploads to S3-compatible storage:
Config.Advanced = {
S3 = {
Enabled = true,
Bucket = "my-bucket",
Region = "us-east-1",
Endpoint = "", -- Leave empty for AWS S3
AccessKey = "your-access-key",
SecretKey = "your-secret-key",
ForcePathStyle = false, -- Set true for MinIO
},
}Auto-apply database migrations on startup:
Config.Migrations = {
AutoApply = true, -- Apply pending migrations automatically
Dir = "pb_migrations",
}PocketBase automatically generates migration files when you modify collections via the admin UI.
All examples use exports['pb']:functionName()
Important: PocketBase must be ready before using any exports. Use the callback or check manually:
exports['pb']:onReady(function()
-- PocketBase is ready, safe to use all exports
local players = exports['pb']:getFullList("players")
end)if exports['pb']:isReady() then
local players = exports['pb']:getFullList("players")
else
print("PocketBase not ready yet!")
endNote: The resource usually takes 1-2 seconds to start. Using onReady() ensures your code runs at the right time.
local collections = exports['pb']:getCollections()local collection = exports['pb']:createCollection({
name = "players",
type = "base",
fields = {
{ name = "username", type = "text", required = true },
{ name = "score", type = "number" },
{ name = "banned", type = "bool" }
}
})exports['pb']:updateCollection("players", { ... })
exports['pb']:deleteCollection("players")-- Delete all records in collection
exports['pb']:truncateCollection("logs")
-- Get collection templates
local scaffolds = exports['pb']:getCollectionScaffolds()local player = exports['pb']:create("players", {
username = "John",
score = 100,
banned = false
})local player = exports['pb']:getOne("players", recordId)-- Paginated
local result = exports['pb']:getList("players", 1, 50)
print(result.totalItems, result.page, result.totalPages)
-- All records
local players = exports['pb']:getFullList("players")local updated = exports['pb']:update("players", recordId, {
score = 150
})exports['pb']:delete("players", recordId)local filter = exports['pb']:filter("score > {:min} && banned = {:banned}", {
min = 100,
banned = false
})
local players = exports['pb']:getFullList("players", { filter = filter })local player = exports['pb']:getFirstListItem("players", "username = 'John'")Perform multiple operations in a single request:
local batch = exports['pb']:batch()
batch = exports['pb']:batchCreate(batch, "players", { username = "Alice", score = 50 })
batch = exports['pb']:batchCreate(batch, "players", { username = "Bob", score = 75 })
batch = exports['pb']:batchUpdate(batch, "players", playerId, { score = 100 })
batch = exports['pb']:batchDelete(batch, "players", oldPlayerId)
local results = exports['pb']:batchSend(batch)Note: Batch API must be enabled in PocketBase Admin > Settings > Batch API
Subscribe to collection changes:
-- Subscribe
exports['pb']:subscribe("players", "*")
-- Listen for events
RegisterNetEvent('pocketbase:players:*', function(data)
print("Action:", data.action) -- "create", "update", "delete"
print("Record:", json.encode(data.record))
end)
-- Unsubscribe
exports['pb']:unsubscribe("players", "*")Subscribe to custom server events:
-- Subscribe
exports['pb']:subscribeToTopic("server_events")
-- Listen
RegisterNetEvent('pocketbase:topic:server_events', function(data)
print("Event:", json.encode(data))
end)
-- Unsubscribe
exports['pb']:unsubscribeFromTopic("server_events")
exports['pb']:unsubscribeByPrefix("server_")Send custom messages from server to connected clients:
-- Send message to all clients subscribed to topic
local sentCount = exports['pb']:sendRealtimeMessage("server_events", {
type = "announcement",
message = "Server restart in 5 minutes"
})
-- Get list of connected clients
local clients = exports['pb']:getRealtimeClients()
print("Connected clients:", #clients)Execute SQL queries directly against the SQLite database:
-- Complex queries with JOINs
local topPlayers = exports['pb']:sqlQuery([[
SELECT users.name, COUNT(orders.id) as total
FROM users
LEFT JOIN orders ON orders.user_id = users.id
GROUP BY users.id
HAVING total > 5
ORDER BY total DESC
]], {})
-- Get single value (COUNT, SUM, etc.)
local totalPlayers = exports['pb']:sqlScalar("SELECT COUNT(*) FROM players")
-- Get single row
local player = exports['pb']:sqlSingle("SELECT * FROM players WHERE id = {:id} LIMIT 1", {id = "abc"})
-- Execute INSERT/UPDATE/DELETE
local insertId = exports['pb']:sqlExecute("INSERT INTO logs (message) VALUES ({:msg})", {msg = "Player joined"})
-- Transaction (all succeed or all fail)
local success = exports['pb']:sqlTransaction({
{sql = "UPDATE accounts SET balance = balance - 1000 WHERE id = {:from}", params = {from = "acc1"}},
{sql = "UPDATE accounts SET balance = balance + 1000 WHERE id = {:to}", params = {to = "acc2"}}
})Execute multiple record operations atomically:
-- All operations succeed or all fail together
local results = exports['pb']:runTransaction({
{type = "create", collection = "players", data = {name = "John"}},
{type = "update", collection = "stats", id = "stat_id", data = {total = 100}},
{type = "delete", collection = "temp_data", id = "temp_id"}
})
print("Created player:", results[1].id)-- Batch fetch by IDs
local players = exports['pb']:findRecordsByIds("players", {"id1", "id2", "id3"})
-- Count records with filter
local activeCount = exports['pb']:countRecords("players", "active = true")Send emails programmatically (requires SMTP configuration):
local success = exports['pb']:sendEmail(
"user@example.com",
"Welcome!",
"<h1>Welcome to the server!</h1>",
"Welcome to the server!" -- Plain text fallback
)For auth-type collections (like users):
local methods = exports['pb']:listAuthMethods("users")local result = exports['pb']:authWithPassword("users", "user@email.com", "password")
print("Token:", result.token)
print("User:", json.encode(result.record))-- Request reset email
exports['pb']:requestPasswordReset("users", "user@email.com")
-- Confirm with token
exports['pb']:confirmPasswordReset("users", token, newPassword, newPasswordConfirm)-- Request verification email
exports['pb']:requestVerification("users", "user@email.com")
-- Confirm with token
exports['pb']:confirmVerification("users", token)-- Get available providers
local methods = exports['pb']:listAuthMethods("users")
-- Authenticate with OAuth2 code
local result = exports['pb']:authWithOAuth2Code("users", "google", code, codeVerifier, redirectUrl)local url = exports['pb']:getFileUrl(record, "avatar.png")local token = exports['pb']:getFileToken()local health = exports['pb']:healthCheck()local ready = exports['pb']:isReady()local url = exports['pb']:getUrl()local connected = exports['pb']:isRealtimeConnected()-- Wait for PocketBase to be ready on resource start
exports['pb']:onReady(function()
print("PocketBase is ready!")
end)
-- Create player on join
AddEventHandler('playerJoining', function()
local source = source
local identifiers = GetPlayerIdentifiers(source)
local player = exports['pb']:create("players", {
identifier = identifiers[1],
name = GetPlayerName(source),
playtime = 0,
joined = os.date("!%Y-%m-%dT%H:%M:%SZ")
})
end)
-- Update playtime on quit
AddEventHandler('playerDropped', function()
local source = source
local identifiers = GetPlayerIdentifiers(source)
local filter = exports['pb']:filter("identifier = {:id}", {id = identifiers[1]})
local player = exports['pb']:getFirstListItem("players", filter)
if player then
exports['pb']:update("players", player.id, {
playtime = player.playtime + 60 -- Add 1 hour
})
end
end)-- Subscribe to ban updates when ready
exports['pb']:onReady(function()
exports['pb']:subscribe("bans", "*")
end)
RegisterNetEvent('pocketbase:bans:*', function(data)
if data.action == "create" then
local ban = data.record
-- Kick player if online
for _, playerId in ipairs(GetPlayers()) do
local ids = GetPlayerIdentifiers(playerId)
if ids[1] == ban.identifier then
DropPlayer(playerId, "You have been banned: " .. ban.reason)
end
end
end
end)-- Get top 10 players
local filter = exports['pb']:filter("banned = false")
local topPlayers = exports['pb']:getFullList("players", {
filter = filter,
sort = "-score", -- Descending
limit = 10
})
for i, player in ipairs(topPlayers) do
print(i, player.name, player.score)
endEnable Batch API in PocketBase Admin > Settings > Batch API
Check firewall settings and port forwarding. This doesn't affect local script access.
Check Config.Superuser credentials in config.lua. Delete and restart to regenerate.
This resource bundles the Windows AMD64 & Linux AMD64 PocketBase binaries, if you wish to download them yourself you can find them here: https://github.com/pocketbase/pocketbase/releases
- PocketBase Docs: https://pocketbase.io/docs/
- JavaScript SDK: https://github.com/pocketbase/js-sdk
- Admin UI: http://127.0.0.1:8090/_/ (when running)