Skip to content

Configuration

The Blixt resource reads config.json from its resource root on startup. Edit the file and restart the resource to apply changes — there is no hot reload yet.

The Lua bootstrap (dist/game/server/config.lua) parses the file with FXServer’s strict JSON parser, so:

  • No comments (// or /* */) — they will fail parsing.
  • No trailing commas.
  • Underscore-prefixed keys (_doc, _comment, _phone_comment) are ignored by the loader’s sanitiser. Use them as inline notes if you want.
  • If parsing fails, the resource boots with defaults and logs [blixt] config.json parse error: <reason>.

A reference copy lives next to config.json as config.example.json — keep it as your working memory of what each field does.


{
"phone": {
/* DeviceConfig */
},
"tablet": {
/* DeviceConfig */
},
"audioRecordingEnabled": true,
"esim": {
/* EsimConfig */
},
"business": {
/* BusinessConfig */
},
"maps": {
/* MapsConfig */
},
"debug": { "enabled": false, "level": "info" }
}

phone and tablet share the same DeviceConfig shape; they’re listed separately because the two devices have independent home layouts, defaults, and disabled-app sets. The tablet supports one extra field, toggleKey.


App IDs to hide on this device. Hidden apps don’t appear on the home screen, in the app switcher, or in the App Store. Use this to replace a built-in app with your own (e.g. ship your own banking resource and add "banking" here to suppress the built-in).

Built-in IDs:

settings, notes, memo, contacts, messages, dialer, calculator, clock,
camera, gallery, bump, fun, social, glimpse, marketplace, bills, calendar,
jobs, garage, mail, banking, govid, store, directory, business, maps,
properties, weather, health

Default: [].

App IDs pinned to the Featured strip at the top of the App Store. Accepts both built-in IDs (above) and external app IDs registered via RegisterExternalApp. Leave empty to show only externally-flagged featured apps.

Default: [].

Initial ordering of icons on the home screen for new characters only. Listed apps come first in the given order; remaining apps follow in registration order. Existing characters with a saved layout are unaffected.

Phone default starts with: ["messages", "contacts", "dialer", "camera", "gallery", "maps", "calendar", "mail"]

Tablet default starts with: ["calendar", "mail", "notes", "marketplace", "garage", "jobs", "directory"]

Additional app IDs whose launchers must remain on the home screen. The default policy already protects the core apps; add to this list when an external app is mission-critical to your server and should be un-removable.

Default: [].

Server-owner-defined wallpapers. Each entry:

{
"id": "company-hq", // required, unique
"url": "https://cdn.example.com/x.webp", // required
"urlLight": "https://cdn.example.com/y.webp", // optional, light-mode variant
"label": "Company HQ" // optional, display name
}

URLs may be:

  • Absolute (https://...) — served from your CDN.
  • Relative — resolved against the device NUI’s html/ folder. To serve a wallpaper from the resource itself, drop the image into resources/blixt/dist/html/wallpapers/x.webp and use "url": "wallpapers/x.webp". Same idea for the tablet’s html/ folder.

defaults.wallpaperId may reference one of these IDs or one of the built-ins: blixt, coast, pier, storm.

Default: [].

First-boot settings applied to new characters only. Existing settings are preserved across config edits. This legacy block covers the three original appearance defaults. New installs should prefer settings.defaults for expanded phone configuration.

{
"theme": "dark", // "light" | "dark"
"language": "en", // any locale code present in the i18n bundle
"wallpaperId": null // string ID or null
}

Blixt currently bundles en (English) and sv (Swedish) as stable locales, plus draft locales for de (German), fr (French), and pt-BR (Portuguese, Brazil). The language value must match one of the bundled locale codes.

Expanded first-boot player setting defaults. These seed new characters only; saved player settings still win after a player has used the phone.

{
"brightness": 80, // 0-100
"notificationSound": "default",
"ringtone": "classic",
"showBatteryPercentage": true,
"textScale": 1, // 0.8-1.4
"reduceMotion": false,
"streamerMode": false,
"skipBootAnimation": false,
"position": "bottom-right", // phone overlay position
"scale": 1, // 0.5-1.5
"marginX": 20,
"marginY": 20
}

Supported keys:

theme, language, wallpaperId, airplaneMode, wifi, bluetooth,
doNotDisturb, brightness, notificationSound, ringtone, scale,
showBatteryPercentage, textScale, reduceMotion, streamerMode,
skipBootAnimation, position, marginX, marginY

Do not put identity or runtime state here. phoneNumber, displayName, flashlight, customWallpaperUrl, faceUnlockEnrolled, and recentSearches are intentionally not config defaults.

The visible device name in the status bar and lock screen. Falls back to the brand default (“Blixt” / “Blixt Tablet”) when absent.

Whether the device may initiate or receive video calls. Defaults differ per device (phone true, tablet false). Set explicitly to override.

tablet.toggleKey: string (tablet-only, optional)

Section titled “tablet.toggleKey: string (tablet-only, optional)”

Default keyboard binding for the /tablet command. Empty string means no default — players can still bind it themselves under FiveM Settings → Key Bindings → Blixt → Toggle Tablet.

FiveM only applies this default on the player’s first encounter; once they’ve bound (or explicitly cleared) it, their choice persists. Use FiveM input names: F2, GRAVE, INSERT, etc.

Default: "".


Server-wide kill switch for in-NUI audio capture. When false, the Memo app is hidden and players cannot record voice memos, voicemail greetings, or voicemail messages. Existing recorded audio can still be played where the UI exposes it.

Default: true.


{
"lineToggleEnabled": true,
"anonymousCallerIdEnabled": true
}
  • lineToggleEnabled controls whether players can activate/deactivate their eSIM line from Settings.
  • anonymousCallerIdEnabled controls whether players can hide outbound call caller ID. SMS/messages still use the real number.

Defaults: both true.


{
"seedArchetypes": true,
"allowPlayerCreate": true
}
  • seedArchetypes seeds the bundled example Businesses on boot.
  • allowPlayerCreate is a legacy direct-create flag. Ordinary player creation now goes through Business Formation; keep this enabled unless you know your server has a custom Business setup.

Defaults: both true.


{
"staticBlips": [
{
"id": "pillbox-hospital",
"label": "Pillbox Hill Medical",
"position": { "x": 358, "y": -592 },
"color": "#ef4444",
"icon": "cross"
}
]
}

staticBlips are server-authored map markers broadcast to every player. id, label, and position are required. color accepts a CSS color, and icon may name a supported lucide icon.

Default: [].


{
"enabled": false,
"level": "info" // "error" | "warn" | "info" | "debug" | "trace"
}

When enabled is true:

  • The Winston logger emits at the configured level.
  • The _dev tRPC router is mounted (used by the dev API and end-to-end test harness).

These can also come from convars blixt:debug and blixt:debugLevel. When those runtime flags are explicitly set, they override config.json so txAdmin/server.cfg can enable or disable development surfaces without editing the resource JSON.

Default: { "enabled": false, "level": "info" }.


A roleplay server that:

  • ships its own banking and messages apps and disables the built-ins
  • features a custom government app on the App Store
  • uses two branded wallpapers
  • defaults new characters to light theme
{
"phone": {
"disabledApps": ["banking", "messages"],
"featuredApps": ["my-gov-app"],
"homeOrder": ["dialer", "my-messages", "contacts", "my-banking", "camera"],
"home": { "requiredApps": ["my-gov-app"] },
"wallpapers": [
{
"id": "skyline-day",
"url": "https://cdn.myserver.com/wp/skyline-day.webp",
"label": "City skyline (day)"
},
{
"id": "skyline-night",
"url": "https://cdn.myserver.com/wp/skyline-night.webp",
"label": "City skyline (night)"
}
],
"defaults": {
"theme": "light",
"language": "en",
"wallpaperId": "skyline-day"
},
"settings": {
"defaults": {
"brightness": 85,
"ringtone": "modern",
"notificationSound": "chime",
"showBatteryPercentage": true,
"position": "bottom-right",
"scale": 1
}
},
"branding": {
"deviceName": "MyServer Phone"
},
"videoCallsEnabled": true
},
"tablet": {
"disabledApps": ["dialer", "bump"],
"featuredApps": [],
"homeOrder": ["mail", "calendar", "marketplace"],
"wallpapers": [],
"defaults": {
"theme": "light",
"language": "en",
"wallpaperId": null
},
"branding": {
"deviceName": "MyServer Tablet"
},
"videoCallsEnabled": false,
"toggleKey": "F2"
},
"audioRecordingEnabled": true,
"esim": {
"lineToggleEnabled": true,
"anonymousCallerIdEnabled": true
},
"business": {
"seedArchetypes": true,
"allowPlayerCreate": true
},
"maps": {
"staticBlips": []
},
"debug": {
"enabled": false,
"level": "info"
}
}

Convars (blixt:framework, the storage providers, blixt:trusted_resources, etc.) live in server.cfg, not in config.json. The split is deliberate:

  • config.json shapes the player-visible product: which apps appear, what wallpapers exist, what the device is called.
  • Convars wire the resource to your infrastructure: framework, storage backends, trust allowlists.

See the convar reference for everything else.