{
  "id": 20222511,
  "title": "Rust Declarative Macros: Organization, Scoping, and Common Use-Cases",
  "url": "https://urgent.news/2026/11/15/rust-declarative-macros-organization-scoping-and-common-use-cases",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-15T19:40:13.000Z",
  "source": {
    "name": "Lobsters",
    "slug": "lobsters",
    "url": "https://sigseis.dev/articles/2026/11/10"
  },
  "original_language": "en",
  "account": "This article, the second in a series, delves into how to incorporate declarative macros into Rust crates. It covers macro scoping, organization, exporting, and provides examples of common use-cases. The article assumes familiarity with the basics of declarative macros and focuses on more advanced techniques.\n\nMacro scoping in Rust can be understood in two ways: textual scoping and path-based scoping. Textual scoping is the default and is based on where the macro is defined within a file. Path-based scoping, on the other hand, treats the macro as an item in the module tree, similar to standard Rust items. While path-based scoping is generally preferred, understanding textual scoping is still valuable as it's widely used.\n\nOne key difference between textual and path-based scoping is that macros with textual scoping must be used within the same module, function, or logical scope where they're defined. They can be used by submodules without explicit import. In contrast, path-based scoped macros can be used before their definition, as they're effectively items in the module tree. This flexibility can make path-based scoped macros more convenient and powerful in certain situations.\n\nVisibility and access rules for textual scoped macros are counter-intuitive. They're only available after their definition within a module, function, or logical scope. However, if defined within the module itself, they're available throughout the module and its submodules. This can be useful for functions with repetitive internal logic, as it keeps the macro close to its usage.\n\nThere are scenarios where you might want a macro to be accessible to modules defined in the parent module. Historically, this was achieved using the #[macro_use] attribute on the containing module. However, this approach has limitations, such as not propagating up the module tree automatically. To address this, you can manually import or resolve the macro after its definition, treating it like any other item. This allows the macro to be used in any module that imports it.\n\nExporting a macro makes it accessible to users of your crate. However, this should be done judiciously, as exported macros can become dependencies for users, complicating changes and maintenance. To export a macro, use the #[macro_export] attribute. When defining a macro for external use, prefer path-based scoping and manually import or resolve it in the desired modules. This approach ensures the macro's usage is clear and flexible.",
  "summary": null,
  "key_points": [
    "Rust declarative macros have two scoping methods: textual and path-based.",
    "Path-based scoping treats macros as module tree items, allowing pre-definition usage.",
    "Exporting macros via #[macroexport] makes them accessible to crate users."
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}