Skip to content

Macros and attributes

Import via factorio_rs or factorio_rs::prelude::*.

Write your own macro_rules! or ship a proc-macro DSL from another crate. factorio-rs expands them with rustc before lowering - see Authoring macros for the pipeline, limitations, and examples.

Built-in Factorio helpers on this page (item!, recipe!, println!, …) keep working both unexpanded (frontend unit tests) and after rustc expansion. locale! is special: its proc macro only typechecks; the CLI still reads locale! from source for .cfg emission.

Applied to a crate, module, or used as *_mod! wrappers:

Attribute / macro Stage
#[factorio_rs::control] / control_mod! Control
#[factorio_rs::settings] / settings_mod! Settings
#[factorio_rs::settings_updates] / settings_updates_mod! Settings updates
#[factorio_rs::settings_final_fixes] / settings_final_fixes_mod! Settings final fixes
#[factorio_rs::data] / data_mod! Data
#[factorio_rs::data_updates] / data_updates_mod! Data updates
#[factorio_rs::data_final_fixes] / data_final_fixes_mod! Data final fixes
#[factorio_rs::shared] / shared_mod! Shared

*_mod! { ... } wraps items in a hidden module marked for that stage (useful from lib.rs).

See Events and filters.

#[factorio_rs::event(OnSingleplayerInit)]
pub fn on_singleplayer_init() {}
#[factorio_rs::event(filter = [OnBuiltEntityFilter::name("inserter")])]
pub fn on_built_entity(event: OnBuiltEntityEvent) {}

Publishes a function as a cross-mod API. Control-stage exports become Factorio remote interfaces; shared exports are requireable and included in the export catalog for consumers. See Sharing code between mods.

#[factorio_rs::export]
pub fn greet(name: &str) {}
#[factorio_rs::export(interface = "my_iface")]
pub fn ping() {}

Marks a shared-stage function as a hot-path library API. Dependents call it via Lua require (same as a shared export), never remote.call. Implies export. Invalid outside shared.

// in src/shared/...
#[factorio_rs::inline]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}

See Sharing code between mods.

See Mod settings.

Declare data-stage item prototypes. Expands to Items name constants (for locale!) and pub fn register() that calls data.extend. Relative icon paths become __{package.name}__/....

Full field tables and stubs: Prototypes. Assets walkthrough: Package graphics.

Declare data-stage recipe prototypes. Expands to Recipes name constants and pub fn register_recipes() that calls data.extend with typed Recipe literals (type = "recipe"; each ingredient/product injects type = "item" unless the ingredient sets fluid = true / type = "fluid"). Ingredient and result name fields accept string literals or paths (Items::WIDGET).

recipe! {
craft_widget {
name = "my-mod-widget",
energy_required = 1.0,
ingredients = [
{ name = "iron-plate", amount = 2 },
],
results = [
{ name = "my-mod-widget", amount = 1 },
],
category = "crafting",
enabled = true,
}
}

Required fields: name, ingredients, results. Optional: energy_required, category, enabled, subgroup, order.

Full guide: Prototypes.

Declare data-stage technology prototypes. Expands to Technologies name constants and pub fn register_technologies() that calls data.extend with typed Technology literals (type = "technology"; each unlock effect injects type = "unlock-recipe"; science packs emit { "pack", amount } tuples).

technology! {
widget_tech {
name = "my-mod-widget",
icon = "graphics/technology.png",
icon_size = 256,
prerequisites = ["automation"],
unlock_recipes = ["my-mod-widget"],
unit_count = 50,
unit_time = 30.0,
unit_ingredients = [
{ name = "automation-science-pack", amount = 1 },
],
}
}

Required fields: name, icon, unlock_recipes, unit_count, unit_time, unit_ingredients. Optional: icon_size, prerequisites, order. Relative icon paths become __{package.name}__/... like item!.

Full guide: Prototypes.

Declare data-stage fluid prototypes (Fluids::* + register_fluids()). Required: name, icon, default_temperature, base_color, flow_color.

Declare assembling-machine entity prototypes (AssemblingMachines::* + register_assembling_machines()). Required: name, icon, crafting_speed, crafting_categories, energy_usage.

Full guide: Prototypes.

Same dual-path pattern (name-const module + register_* + typed stub). Macros emit sparse tables; fill complex Factorio fields via hand-written data.extend when needed. Full field notes: Prototypes.

Macro Const module Register fn Stub
container! Containers register_containers Container
inserter! Inserters register_inserters Inserter
transport_belt! TransportBelts register_transport_belts TransportBelt
furnace! Furnaces register_furnaces Furnace
mining_drill! MiningDrills register_mining_drills MiningDrill
lab! Labs register_labs Lab
resource! Resources register_resources ResourceEntity
tile! Tiles register_tiles Tile
autoplace_control! AutoplaceControls register_autoplace_controls AutoplaceControl
recipe_category! RecipeCategories register_recipe_categories RecipeCategory
item_group! ItemGroups register_item_groups ItemGroup
item_subgroup! ItemSubgroups register_item_subgroups ItemSubgroup
module! Modules register_modules Module

Import stubs such as Container via factorio_rs::prelude::prototypes::Container (or factorio_api::prototypes).

See Locale.

In executable code, println!, format!, matches!, (with the tracing feature) tracing::{error,warn,info,debug,trace}!, and (with the serde feature) serde_json::{to_string,from_str,...} calls are lowered:

  • println!(...) -> game.print(...)
  • format!(...) -> Lua string concatenation with ..
  • matches!(expr, pat) / matches!(expr, pat if guard) -> value match -> true / false
  • tracing::info!(...) / warn! / … -> colored game.print (see Tracing)
  • serde_json::to_string / … -> helpers.table_to_json / string.pack (see Serde / JSON)

Item macros such as mod_settings!, item!, recipe!, technology!, fluid!, assembling_machine!, container!, inserter!, and locale! are handled separately during module lowering.

Full syntax inventory: Supported Rust.