Packages & DLC

Three flavours of bundle, one underlying format. Drop-in DLC, third-party add-ons, and the project itself all ship as encrypted .managed files; only the layout around them differs.

The .managed format

A .managed file is one of two kinds:

Both are AES-256-GCM encrypted with a key baked into the engine binary. The encryption is intentional but not cryptographic protection, it's there to keep casual asset rippers out, not to defeat a determined extractor.

Loading order

At launcher startup the engine scans Managed/ next to the executable and loads every .managed file. Each file's declared id ("id" in ManagedInfo.toml or the project's exe-name) becomes a require namespace. The package whose id matches the launcher's default_id trailer field is the entry, it's what runs when the launcher boots.

Generated/
    MyGame.exe                              # launcher; default_id = "MyGame"
    Managed/
        MyGame.scripts.managed              # ← entry: id = "MyGame"
        MyGame.assets.managed
        Physics.scripts.managed             # DLC: id = "Physics"
        Physics.assets.managed
        community-mod.scripts.managed       # Workshop drop-in

require() across packages

Every package gets its own require namespace prefixed with @id/:

-- From inside MyGame:
local phys   = require("@Physics/init")       -- DLC API
local common = require("@self/lib/util")      -- own package, root-relative
local sib    = require("./helper")             -- caller-relative

@self is an alias for the calling script's own package id , useful in DLC code that doesn't know the project name.

DLC: built-in side packages

A DLC is a folder inside your project that contains a ManagedInfo.toml. ruzit build auto-discovers them and packages each one alongside the project:

MyGame/
    build.toml
    Main.luau
    assets/
    Physics/                          # ← DLC folder
        ManagedInfo.toml
        init.luau
        body.luau
        assets/

ManagedInfo.toml:

id      = "Physics"
name    = "Physics DLC"
version = "1.1.0"
creator = "Studio Name"
entry   = "init.luau"
"File Type" = "Relative"

include = [
    "PhysicsLicense.txt",
    "reference-data/",
]

Scaffold a fresh DLC folder with ruzit initpackage Physics.

Native side files: bin/ and include

A DLC folder can ship native libraries and other non-Luau side files just like the host project. Two mechanisms, both convention-driven and merged into the final build:

Physics/                          # ← DLC folder
    ManagedInfo.toml              # declares include = ["PhysicsLicense.txt", ...]
    init.luau
    bin/
        ruzit_physics_solver.dll  # → Generated/bin/ruzit_physics_solver.dll
    PhysicsLicense.txt            # → Generated/PhysicsLicense.txt (via include)
    reference-data/
        materials.json            # → Generated/reference-data/materials.json
Merge order. When two packages drop libraries with the same filename into bin/, last-write-wins (DLCs first, external folder packages after). Don't rely on which is which — rename your DLL to something namespaced (ruzit_ffi_studio_physics.dll) rather than a generic solver.dll.

External packages: Workshop / mods

Third-party packages live as .managed files in a Packages/ folder, either in the project root (during ruzit test) or next to the launcher (after ruzit build). They're loaded the same way DLC is, but aren't bundled into the project's launcher, they're drop-ins.

MyGame/
    build.toml
    Main.luau
    Packages/
        community-mod.scripts.managed     # pre-built bundle
        community-mod.assets.managed
        ffi-physics-pack/                 # loose folder package
            ManagedInfo.toml
            init.luau
            bin/
                physics_native.dll

Producers ship their package one of two ways:

Conflict resolution. If a third-party package's id matches a DLC or the project itself, the launcher prefers the project, the third-party file is skipped with a warning. This stops malicious mods from shadowing your scripts.

Patching

With shard-assets = true in build.toml, the asset bundle splits into ~64 MB shards keyed by content. Patches only have to re-download the shards whose content changed; the manifest file lists which assets are in which shard, so the player's launcher can decide what to fetch.

Scripts always ship as a single .scripts.managed per package, sharding compiled bytecode rarely pays off.