`fivem-cfg`: write your FiveM server.cfg in TypeScript.

fivem-cfg

NPM Version

Write your FiveM server.cfg in TypeScript. Get type-checking, autocomplete and a generated configuration file through a CLI or programmatically.

CLI


// server.config.ts
import { defineServer } from "fivem-cfg";

export default defineServer({
  hostname: "My RP Server",
  maxClients: 64,
  oneSync: "on",
});


pnpx fivem-cfg --input server.config.ts --output server.cfg

This generates a server.cfg file with the following content:


# autogenerated by fivem-cfg

set sv_hostname "My RP Server"
set sv_maxClients "64"

Programmatic


import { defineServer } from "fivem-cfg";

const cfg = defineServer({
  hostname: "My RP Server",
  maxClients: 64,
  oneSync: "on",
  enforceGameBuild: 3751,
  endpoints: { tcp: ["0.0.0.0:30120"], udp: ["0.0.0.0:30120"] },
});

console.log(cfg.generate()); // prints server.cfg content

Install


pnpm add fivem-cfg

Configuration Options

All configuration options and their descriptions are documented as JSDoc annotations in src/schema.ts.

The schema covers all officially documented server-commands. Use the set/sets/setr (see “Convars”) escape hatches for any convars not in the schema:


defineServer({
  set: { sv_scriptHookAllowed: "1" },
  sets: { tags: "roleplay, english", locale: "en-US" },
});

2 Likes

I’m just wondering (not hating) whats a good practical use of this?

1 Like

This is mostly useful if you want to generate environment-dependent configuration (e.g. you want a different hostname based on process.env.NODE_ENV ) .

This is how I am using the library:

import { defineServer } from "fivem-cfg";

const withEnv = <K>(args: { dev: K; prod: K }) =>
    process.env.FIVEM_ENVIRONMENT === "production" ? args.prod : args.dev;

export default defineServer({
    licenseKey: process.env.FIVEM_LICENSE_KEY,
    hostname: withEnv({
        dev: "Test Server | Development",
        prod: "Test Server",
    }),
    projectName: withEnv({
        dev: "Test Server | Development",
        prod: "Test Server",
    }),
    projectDesc: "A test server",
    maxClients: withEnv({
        dev: 1,
        prod: 48,
    }),
    endpoints: {
        tcp: ["0.0.0.0:30120"],
        udp: ["0.0.0.0:30120"],
    },
    ensure: ["test"],
    sets: {
        tags: "roleplay",
        locale: "en-US",
    },
});
1 Like

Maybe for type safety and keeping everything in one place? That’s the main advantage I can think of.

2 Likes

This is actually a really interesting idea

1 Like