Quasar Framework (qs-core) ships a complete FiveM vehicle system for roleplay servers: vehicle keys with lock, unlock and hotwiring, 31 garages with a 3D preview, a car dealership with a showroom, and admin tools to spawn, repair and delete vehicles. Every owned car lives in one vehicles table, so the keys, the garages, the dealership and your own scripts all agree on who owns what — whether the rest of your server runs ESX, QBCore or Quasar Framework scripts.
Nothing here needs a single line of code to get running: the txAdmin recipe starts every resource, and everything you might want to change is in a Lua config.lua.
Resource | Folder | What it does |
|---|---|---|
|
| Keys per plate, lock and unlock, engine blocked without keys, hotwiring with a lockpick, |
|
| 31 garages with map blips, a vehicle list with a turntable 3D preview, take out and store. |
|
| Dealership with a salesman, category tabs, live preview and instant delivery. |
|
| The |
|
| Compatibility shims so QBCore and ESX scripts find the keys and fuel APIs they expect. |
Vehicle controls at a glance#
Key / command | Who | What it does |
|---|---|---|
| Everyone | Lock or unlock the vehicle you are in, or the closest one within 5 m. Needs its keys. |
| Everyone | Hotwire the keyless vehicle you are driving. Needs a |
| Everyone | Give a copy of the keys of the vehicle you are sitting in. |
| Everyone | On foot: open the garage. Driving: store the vehicle. |
| Everyone | Open the showroom. |
| Admins | Give keys of the vehicle you are sitting in to yourself or a player. |
| Admins | Spawn a vehicle with keys / delete the nearest vehicle. |
U and G are FiveM key mappings: each player can rebind them in Settings → Key Bindings → FiveM. The E prompts use the game's context key and are not rebindable.
FiveM vehicle keys (qs-corevehiclekeys)#
Keys belong to a plate. If you sit in the driver seat of a vehicle whose plate you have no keys for, the engine is held off and you cannot drive away — you need the keys, or a lockpick and steady hands. Passengers are never blocked.
Who gets keys#
Source | When you get the keys |
|---|---|
Owning the vehicle | You sit in the driver seat of a car registered to your character. Quasar Framework checks the |
Garage | You take a vehicle out of a garage. |
Dealership | Your new car is delivered. |
Job vehicles | You take a car from the police or EMS garage, or start a delivery shift and get the van. |
Hotwiring | You win the lockpick minigame. |
Another player | They run |
Admin | An admin runs |
Scripts | Any script calls |
Driving without keys#
When you are the driver and have no keys, the engine is switched off and kept from starting on its own. A help prompt tells you what to do:
With a lockpick in your inventory: "Hold G to hotwire".
Without one: "You need keys to drive this. Get a lockpick to hotwire it".
As soon as you get the keys — from the owner check, a friend, an admin or a successful hotwire — the block is lifted within half a second and you can start the engine. Set Config.RequireKeysToDrive = false if you want anyone to drive any car.
Lock and unlock (U)#
Press U to toggle the locks:
Inside a vehicle, it acts on that vehicle. On foot, it acts on the closest vehicle within 5 m (
Config.LockDistance).You need the keys of that plate, otherwise you see "You don't have keys for this vehicle".
On foot your character clicks the key fob, the lights flash, and you get "Vehicle locked" or "Vehicle unlocked".
The new lock state is synced to every player on the server.
Keys also guard the vehicle's storage in qs-coreinventory: the trunk opens only if the vehicle is unlocked and you hold its keys, and the glovebox needs the keys. See Inventory, Items & Weapons.
Hotwiring with a lockpick (G)#
Hotwiring is how you steal a car in Quasar Framework. You need to be the driver of a keyless vehicle and carry at least one lockpick (sold at the Hardware Store for $35).
Get in the driver seat
Sit in a car you have no keys for. The engine stays off and, with a lockpick on you, the prompt invites you to hotwire it.
Press G
The lockpick minigame opens. A pick sweeps around a ring: press SPACE while it is inside the highlighted zone to set the pin.
Beat every round
The default is 3 rounds (
Config.HotwireRounds, from 1 to 6). Each round the zone gets smaller and the pick faster. One miss ends the attempt. ESC or Backspace cancels, and after 30 seconds the attempt fails on its own.Drive away — or run
On success you get the keys, the engine starts and you see "The engine roars to life".
When the attempt fails (a miss, a cancel or the timeout):
One
lockpickis removed from your inventory (Config.BreakLockpickOnFail) and you see "The lockpick snapped".The vehicle's alarm goes off.
If
qs-policeis running, every police officer gets a "Vehicle break-in reported" alert at your position. Alerts are limited to one every 8 seconds per player, so spamming attempts does not flood the police.
See Jobs, Police & EMS for the police side of the alert.
Sharing keys with /givekeys#
Sit in the vehicle (any seat) and make sure you hold its keys, then:
Command | Who receives the keys |
|---|---|
| The nearest player within 5 m ( |
| The player with server id |
Giving keys hands over a copy — you keep yours. You see "You handed over the keys" and the other player sees "You received vehicle keys".
Admin keys with /adminkeys#
Admins can give themselves or anyone the keys of the vehicle they are sitting in:
/adminkeys # keys for you
/adminkeys 12 # keys for player 12You must be sitting in the vehicle ("You are not in a vehicle" otherwise), and the target must be online ("No one nearby" otherwise). The command needs the command.adminkeys ACE, which add_ace group.admin command allow in the shipped server.cfg already grants. It does nothing from the server console. See Administration.
Keys after a reconnect#
Keys live in the player's game session and are not saved. After a reconnect (or a restart of qs-corevehiclekeys):
Owned vehicles: nothing to do. The first time you sit in the driver seat, the owner check gives you the keys back.
Every other key (from
/givekeys, hotwiring,/caror the admin menu): gone. Ask the owner again, hotwire again, or ask an admin.
The lock state of a vehicle is not saved either.
Vehicle keys configuration#
File: [core]/qs-corevehiclekeys/config.lua
Option | Default | What it does |
|---|---|---|
|
| Hold the engine off for a driver without keys. |
|
| Give owners their keys automatically when they sit in the driver seat. |
|
| Default key of the lock / unlock mapping. |
|
| How close you must be to lock a vehicle on foot. |
|
| Item needed to hotwire, and the one removed on failure. |
|
| Default key of the hotwire mapping. |
|
| Minigame rounds, from 1 (easy) to 6 (hard). |
|
| Remove one lockpick when hotwiring fails. |
|
| Range of |
Performance#
The key system is built for a low resmon. A single check runs every 500 ms — nothing runs every frame. Ownership is asked from the server once per plate per session, and lock changes are only sent when someone presses the key. Nothing is written to the database.
FiveM garages (qs-garage)#
Players park and retrieve their cars at 31 garages spread across Los Santos, Blaine County and Paleto Bay. Each garage is marked on the map with a blue Garage blip, and opening one shows your cars in a cinematic 3D preview on a turntable.
Garage locations#
Area | Garages (id) |
|---|---|
Downtown Los Santos | Legion Square ( |
Vinewood & Mirror Park | Vinewood West ( |
West side & beaches | Spanish Ave Parking ( |
South & East Los Santos | Elysian Parking ( |
Airport | Airport Los Santos ( |
Blaine County | Penitentiary ( |
Paleto Bay | Paleto Bay Parking ( |
Every garage is public: there are no job or gang garages, and every player sees every blip. The id in brackets is what is saved in the garage column of the vehicles table.
Opening a garage#
Walk up to the garage point. Within 3 m you see "Press E to open the garage". Press E and:
Your character is frozen in place and the HUD hides.
The camera glides to the garage's preview spot and your first car appears on a slowly turning platform.
The menu lists each car with its plate, its status (Stored or Out), fuel, engine and body condition.
Click a car to preview it: the current one fades out and the new one fades in, with its real colours and mods.
Press Take out, or Close to leave.
The preview car is only visible to you. If you own nothing here, the menu shows "No vehicles in this garage."
Which vehicles a garage lists#
A garage lists:
every car of your character stored in this garage, whether it is currently in or out;
plus every car of yours that has no valid garage — a car you bought at the dealership and have not stored yet, or a car whose garage was removed or renamed in the config. These show up in every garage and can be taken out from any of them. Storing them anywhere gives them that garage as their new home.
Cars belong to your character, not your account: each character in multicharacter has its own garage contents.
Taking a vehicle out#
Select a car and press Take out. The garage checks that:
The car belongs to your character.
It belongs to this garage, or to no valid garage.
It is not already out in the world.
The car then appears at the garage's spawn point with its plate, saved colours and mods, saved engine and body damage and saved fuel. It is cleaned, unlocked, you get the keys, and you are placed in the driver seat with "Vehicle taken out". The car is marked Out in the database.
The garage does not clear the spawn point before spawning, so keep spawn points where players do not usually park.
Storing a vehicle#
Drive into any garage point. Within 3 m you see "Press E to store this vehicle". Press E:
You must be the driver ("You must be in the driver seat" otherwise).
The car must be registered to your character. Having its keys is not enough: a friend's car, a hotwired car or a car spawned with
/caris refused with "This is not your vehicle".Any garage works, whichever garage the car came from. The garage you store it in becomes its home.
The car's current state is saved, the vehicle disappears and you see "Vehicle stored".
What a garage saves#
Saved | Details |
|---|---|
Garage | The id of the garage you stored it in. |
Status | Stored ( |
Fuel | Whole number from 0 to 100. |
Engine health | Restored on take-out, so a broken engine stays broken. |
Body health | Restored on take-out. |
Colours | Primary, secondary, pearlescent and wheel colour. |
Wheels and glass | Wheel type and window tint. |
Plate style and livery | Plate background and the vehicle livery. |
Modifications | Mod slots 0–49 (bodywork, engine, brakes, transmission, suspension, armour, wheels…). |
Extras | Each vehicle extra on or off. |
Adding a garage#
You can add garages in two places. garages.lua holds the 31 default garages in a one-line format and builds the id, label, blip and prompt position for you. config.lua takes the full format when you want your own id or a different blip.
Collect the three positions
Use the admin command
/coordsat each spot. It printsvec4(x, y, z, heading)in the F8 console and on screen.Menu point: where players press E. Players also drive into this point to store.
Spawn point: where taken-out cars appear. Face the way the car should leave.
Preview point: where the 3D preview car stands. The camera sits 5.2 m in front of the car along this heading, so face the heading toward open space.
Add the garage
lua -- [addons]/qs-garage/garages.lua, inside the `extra` table { name = 'Beach House Garage', menu = vec3(-1520.40, -430.10, 35.44), spawn = vec4(-1515.20, -425.80, 35.20, 230.0), preview = vec4(-1530.00, -440.00, 35.30, 140.0) },The id is generated from the name:
beach_house_garage. The blip is the standard blue Garage blip.lua -- [addons]/qs-garage/config.lua Config.Garages = { { id = 'beach_house', -- unique, saved in vehicles.garage label = 'Beach House Garage', -- title of the garage menu coords = vec4(-1520.40, -430.10, 35.44, 0.0), -- menu point (heading unused) spawn = vec4(-1515.20, -425.80, 35.20, 230.0), -- where cars appear preview = vec4(-1530.00, -440.00, 35.30, 140.0), -- where the preview car stands blip = { sprite = 357, color = 3, scale = 0.5, label = 'Garage' }, -- remove for no blip }, }The 31 default garages from
garages.luaare added after yours.Restart the garage
Run
restart qs-garagein the server console (or restart the server). The list of valid garage ids is built when the resource starts.
Garage configuration#
File: [addons]/qs-garage/config.lua
Option | Default | What it does |
|---|---|---|
|
| Control used to open and store (38 = E). A GTA control index, not a key mapping. |
|
| Distance to the menu point for the prompt. |
|
| Camera distance in front of the preview car. |
|
| Sideways camera offset. |
|
| Camera height above the preview point. |
|
| Height of the point the camera looks at. |
|
| Camera field of view. |
|
| Turntable speed in degrees per second. |
|
| Your own garages (format above). The 31 default garages are appended from |
The garage loop sleeps 1.5 s when you are more than 40 m from every garage and only draws the prompt every frame while you stand within 3 m of one.
FiveM car dealership (qs-vehicleshop)#
The dealership sells cars straight to players. It sits at Premium Deluxe Motorsport in downtown Los Santos, marked with a Dealership blip, where a salesman waits with his clipboard.
Buying a vehicle#
Talk to the salesman
Walk up to him. Within 2.5 m you see "Press E to browse the dealership". Press E.
Browse the showroom
Your character is frozen and the HUD hides. The camera moves to the showroom floor, where the first car of the first category turns on a platform. The menu shows the category tabs, the cars with their prices, and your cash and bank balances.
Preview
Click any car to swap the showroom car, with a short fade between them. Showroom cars carry the plate
SHOWROOMand only you can see them.Buy
Press Buy. The price comes from the server's catalogue, never from the player's game, and the server checks that you are still at the dealership.
Drive away
You see "Vehicle purchased! Plate: QS…", the showroom closes and your new car waits at the delivery point with a full tank, clean and unlocked. You get the keys and are placed in the driver seat.
Message | Why |
|---|---|
"You cannot afford this vehicle" | No payment account has the full price. |
"You are too far from the dealership" | The server found you more than 12.5 m from every dealership salesman. |
"Purchase failed" | The model is not in the catalogue, you clicked Buy twice within 1.5 s, or no free plate was found. |
Payment and plates#
Payment: the accounts in
Config.PayAccountsare tried in order —bankfirst, thencash. The first account that holds the full price pays it all; a price is never split across accounts. The transaction is recorded with the reasonvehicleshop:<model>.Plate:
QSfollowed by 5 random letters and digits (for exampleQS7K2XA), checked against the database so it is unique.
After the purchase: storing your new car#
The car is saved as yours immediately, marked Out, with the garage legion (Config.DefaultGarage). legion is not one of the 31 garage ids, so until you park it the car shows up in every garage:
Drive it to any garage and store it from the driver seat. That garage becomes its home.
If you lose it before storing it (destroyed, server restart…), open any garage and take it out again.
Want new cars to belong to a specific garage instead? Set Config.DefaultGarage to one of the garage ids, for example 'pillbox_hill_garage'. New cars are then listed only in that garage.
Default catalogue#
Category | Model | Label | Price |
|---|---|---|---|
Compacts |
| Dinka Blista | $9,000 |
Compacts |
| Grotti Brioso | $18,000 |
Compacts |
| Weeny Issi | $16,000 |
Compacts |
| Benefactor Panto | $8,500 |
Sedans |
| Declasse Asea | $12,000 |
Sedans |
| Declasse Premier | $15,000 |
Sedans |
| Vapid Stanier | $14,000 |
Sedans |
| Vulcar Warrener | $17,000 |
SUVs |
| Gallivanter Baller | $55,000 |
SUVs |
| Declasse Granger | $38,000 |
SUVs |
| Albany Cavalcade | $42,000 |
Sports |
| Karin Sultan | $45,000 |
Sports |
| Karin Kuruma | $52,000 |
Sports |
| Annis Elegy RH8 | $60,000 |
Sports |
| Dinka Jester | $78,000 |
Off-Road |
| Vapid Sandking | $40,000 |
Off-Road |
| Karin Rebel | $22,000 |
Off-Road |
| Canis Kalahari | $18,000 |
Motorcycles |
| Dinka Akuma | $14,000 |
Motorcycles |
| Pegassi Bati 801 | $20,000 |
Motorcycles |
| Maibatsu Sanchez | $9,000 |
Adding vehicles and categories#
Add the category
Categories appear as tabs in the order you list them. The first car of the first category is the one shown when the showroom opens.
lua -- [addons]/qs-vehicleshop/config.lua Config.Categories = { { id = 'compacts', label = 'Compacts' }, -- ... { id = 'muscle', label = 'Muscle' }, }Add the vehicles
Add a list under the category id.
modelis the spawn name,labelis what players read,priceis in dollars.lua Config.Vehicles = { -- ...existing categories... muscle = { { model = 'dominator', label = 'Vapid Dominator', price = 35000 }, { model = 'gauntlet', label = 'Bravado Gauntlet', price = 32000 }, }, }List each model only once across all categories.
Restart the dealership
Run
restart qs-vehicleshopin the server console.
Adding another dealership#
Add a second entry inside Config.Locations, after the default one. Every dealership sells the same catalogue.
-- [addons]/qs-vehicleshop/config.lua, a new entry inside Config.Locations
{
ped = 's_m_m_autoshop_02', -- salesman model (optional)
coords = vec4(-1255.00, -361.00, 36.91, 300.0), -- salesman and prompt position
preview = vec4(-1265.00, -355.00, 36.90, 120.0), -- showroom car
spawn = vec4(-1240.00, -370.00, 37.00, 30.0), -- delivery point
blip = { sprite = 326, color = 3, scale = 0.6, label = 'Dealership' }, -- optional
},Use /coords to get each position. Without ped there is no salesman; without blip there is no map marker.
Dealership configuration#
File: [addons]/qs-vehicleshop/config.lua
Option | Default | What it does |
|---|---|---|
|
| Control used to open the showroom (38 = E). |
|
| Prompt distance to the salesman. Buying is allowed up to |
|
| Accounts tried in order; the first one with the full price pays. |
|
| Garage saved on new cars. |
|
| Showroom camera, same meaning as in the garage. |
| 1 dealership | Dealerships: |
| 6 categories | Tabs |
| 21 vehicles | Catalogue by category id: |
Admin vehicle tools#
Admins (anyone with the command.qs ACE) get a set of vehicle tools through commands and the admin menu on F6. See Administration for how to become an admin.
Tool | How | What it does |
|---|---|---|
Spawn a car |
| Spawns the model where you stand, puts you in the driver seat, sets a |
Spawn a car (menu) | F6 → Self → Spawn Vehicle | Clears the way first: deletes the car you are in and any empty car within 3 m of you or of the spawn point, 3 m in front of you (cars with another player inside are left alone). Then spawns the model with a full tank, puts you in the driver seat and gives you the keys. |
Delete a car |
| Deletes the car you are in, or the closest one within 5 m. |
Delete a car (menu) | F6 → Self → Delete Vehicle | Deletes the car you are in, or the closest one within 6 m. |
Repair | F6 → Self → Fix Vehicle | Fully repairs the car you are in: engine, body, deformation and dirt. |
Clear the area | F6 → Self → Clear Area | Removes vehicles and objects within 30 m of you. |
Keys |
| Keys of the car you are sitting in, for you or a player. |
Fuel#
The [bridge] folder includes a LegacyFuel-compatible shim, so scripts and the HUD that read exports['LegacyFuel']:GetFuel(vehicle) work out of the box. While you drive, the engine burns fuel (more at high RPM), and at 0 the engine shuts off. Garages save the fuel level and restore it on take-out; dealership and admin-menu cars start with a full tank. The shim has no fuel pumps or jerry cans of its own. See Integrations for fuel scripts.
The vehicles table#
Every owned vehicle is one row of the vehicles table, created by qs-core/sql/qscore.sql.
Column | What it stores |
|---|---|
| Owner character. |
| Owner's |
| Plate, unique. |
| Spawn name, lower case. |
| Garage id (default |
|
|
| 0–100. |
| Health, 1000 = perfect. |
| Colours, mods and extras, as JSON. |
ESX and QBCore vehicle scripts#
The [bridge]/qb-vehiclekeys shim answers as qb-vehiclekeys and forwards everything to qs-corevehiclekeys:
Client exports
GiveKeys(plate),RemoveKeys(plate),HasKeys(plate),GetKeys().Client events
vehiclekeys:client:SetOwner,qb-vehiclekeys:client:AddKeys,qb-vehiclekeys:client:GiveKeys,qb-vehiclekeys:client:RemoveKeys.Server events
qb-vehiclekeys:server:AcquireVehicleKeysandqb-vehiclekeys:server:GiveVehicleKeys, and the server exportGiveKeys(source, plate).
QBCore scripts that hand out keys after a job, a rental or a heist therefore give real Quasar Framework keys. QBCore's player_vehicles table does not exist: owned cars are in vehicles, and exports['qs-core']:GetPlayerVehiclesQBShape(citizenid) returns them in the player_vehicles shape. QBCore garages or vehicle shops that run their own SQL on player_vehicles are not supported — use qs-garage and qs-vehicleshop.
The ESX bridge creates ESX's owned_vehicles table so scripts that expect it start cleanly, but Quasar Framework keeps owned cars in vehicles, and owned_vehicles stays empty. ESX garages or vehicle shops that run their own SQL on owned_vehicles are not supported — use qs-garage and qs-vehicleshop. ESX scripts that only spawn vehicles keep working; give the player keys with the GiveKeys export if the car should be drivable.
See ESX & QBCore Compatibility for everything the bridges cover.
For developers#
GiveKeys / RemoveKeys / HasKeys / GetKeys (client)
local plate = GetVehicleNumberPlateText(vehicle)
exports['qs-corevehiclekeys']:GiveKeys(plate)
if exports['qs-corevehiclekeys']:HasKeys(plate) then
-- the local player can drive and lock this vehicle
end
exports['qs-corevehiclekeys']:RemoveKeys(plate)
local all = exports['qs-corevehiclekeys']:GetKeys() -- { [plate] = true }Plates are compared without trailing spaces. Keys are session-only.
Give keys from the server
TriggerClientEvent('vehiclekeys:client:SetOwner', source, plate)Same event name as qb-vehiclekeys, so QBCore scripts already use it. qs-corevehiclekeys:client:give and qs-corevehiclekeys:client:remove (argument plate) are also available.
GetCitizenVehicles / GetOwnedVehicles (server)
local cars = exports['qs-core']:GetCitizenVehicles(citizenid)
for _, car in ipairs(cars) do
print(car.plate, car.model, car.garage, car.state, car.fuel)
endEvery row of vehicles owned by that character, with props already decoded. GetOwnedVehicles(citizenid) returns the same. GetGarageVehicles(citizenid, garage) filters by garage id.
GetVehicleByPlate / PlateExists (server)
local car = exports['qs-core']:GetVehicleByPlate('QS7K2XA') -- row or nil
local taken = exports['qs-core']:PlateExists('QS7K2XA') -- booleanCreateOwnedVehicle — give a player a car (server)
local player = exports['qs-core']:GetPlayer(source)
exports['qs-core']:CreateOwnedVehicle({
citizenid = player.citizenid,
license = GetPlayerIdentifierByType(source, 'license'),
plate = 'QSGIFT1',
model = 'sultan',
garage = 'legion_square',
state = 1, -- 1 = parked in the garage
})Defaults: garage = 'legion', state = 1, fuel = 100, engine and body = 1000.0, props = {}. Check the plate with PlateExists first: plates are unique.
UpdateOwnedVehicle / SetVehicleState (server)
exports['qs-core']:UpdateOwnedVehicle(plate, { garage = 'legion_square', state = 1, fuel = 80, engine = 1000.0, body = 1000.0, props = {} })
exports['qs-core']:SetVehicleState(plate, 1, 'legion_square') -- garage is optionalUpdateOwnedVehicle writes all six fields at once, so always pass garage and state along with the values you want to keep (read them first with GetVehicleByPlate).
SpawnVehicle (server)
local netId = exports['qs-core']:SpawnVehicle(source, 'sultan', vector4(x, y, z, heading), true)Creates the vehicle on the server and, with true, warps the player into the driver seat. Returns the network id, or nil if the vehicle could not be created. It does not give keys.
Driving it from your own scripts? Every command, keybind, export and event is listed in Commands and Exports. Something not behaving? Check Common Errors.



