Sharing code between mods
Want mod B to call a function from mod A? Mark it with #[factorio_rs::export],
build A, then add A as a normal Cargo dependency. Call it like any Rust
crate: provider::greet("hi").
# In the library modfactorio-rs build# writes [package.metadata.factorio] + src/factorio_exports.rs (+ lib.rs wiring)
# In the dependent mod (preferred: also merges Factorio.toml deps):factorio-rs add ../provider# or Cargo-only (you must add the Factorio dep yourself):cargo add --path ../provider
factorio-rs buildWorking tree: provider / consumer example.
Export a function (library mod)
Section titled “Export a function (library mod)”Only items marked with #[factorio_rs::export] are visible to other mods. Plain
pub stays private to your transpile (not a Cargo API by itself).
Use pub mod for stage modules you want dependents to see:
pub mod shared;
#[factorio_rs::control]pub mod control { #[factorio_rs::export] pub fn greet(name: &str) { println!("hello, {name}"); }}You can also put #[factorio_rs::export] on a whole mod to export every pub fn
inside it.
After factorio-rs build, factorio-rs:
- Registers control exports with Factorio (
remote.add_interface) - Keeps shared exports loadable via Lua
require - Writes
[package.metadata.factorio]on yourCargo.toml(so Cargo dependents are discovered) - Regenerates
src/factorio_exports.rsand wiresmod factorio_exports; pub use factorio_exports::*;intolib.rswhen missing
Control vs shared
Section titled “Control vs shared”| Where you export | How other mods call it |
|---|---|
Control stage (#[factorio_rs::control]) |
Live call into your mod: remote.call |
Shared stage (shared/...) + #[factorio_rs::export] |
Load your Lua module: require |
Shared stage + #[factorio_rs::inline] |
Same require path (hot helpers; never remote) |
Use #[factorio_rs::inline] on pure shared helpers (for example add(a, b)) so dependents
bind via require instead of paying remote.call. It implies export and is only
valid in shared. Stateful cross-mod APIs stay on control with #[factorio_rs::export].
Optional: rename the Factorio remote interface with
#[factorio_rs::export(interface = "math")] or bare #[factorio_rs::export(interface)].
#[factorio_rs::inline]pub fn add(a: i32, b: i32) -> i32 { a + b}// consumeruse provider::shared::api;let n = api::add(2, 3); // -> require("__provider__/lua/shared/api"); api.add(2, 3)Depend through Cargo
Section titled “Depend through Cargo”[dependencies]provider = { path = "../provider" }# or a crates.io / git dependency once you publish the packagefactorio-rs add ../provider is a thin helper that adds that path dep and merges
Factorio.toml dependency strings from the library’s metadata.
Then call:
#[factorio_rs::control]mod control { use provider::shared::api;
#[factorio_rs::event(OnSingleplayerInit)] pub fn on_init() { provider::greet("world"); // -> remote.call("provider", "greet", ...) api::greet("world"); // -> require("__provider__/lua/shared/api") }}Notes:
- Root names like
provider::greetare control/remote exports (viafactorio_exports.rs). - Paths like
provider::shared::...are shared/requireexports (real modules in the library crate). - At transpile time, those calls become
remote.call/require- the library’s Rust bodies are not copied into your mod’s Lua. factorio-rs check/buildruncargo checkon that real library package (and rust-analyzer does the same in the editor).
Other Factorio deps (optional)
Section titled “Other Factorio deps (optional)”Non-Rust Factorio deps (DLC, conflicts) still go in Factorio.toml:
[mod]factorio_version = "2.0"dependencies = ["? space-age"]factorio-rs add appends entries like provider >= 0.3.0 from Cargo metadata.
A base >= ... line is added automatically when missing.
Lua-only mods (flib, etc.)
Section titled “Lua-only mods (flib, etc.)”Publish or path-depend a small crate with empty pub fn stubs and
[package.metadata.factorio] - same shape the toolchain writes for factorio-rs
libraries.
Troubleshooting
Section titled “Troubleshooting”| Problem | Fix |
|---|---|
library exports missing / no metadata |
Run factorio-rs build in the library first |
provider::greet not found |
Ensure pub mod control, rebuild the library (regenerates/wires factorio_exports) |
| Call doesn’t update after changing exports | Rebuild the library, then rebuild the dependent |