Skip to content

Imports and modules (how-to)

This page shows how to structure multi-file projects and use imports in practice.

Prerequisite: follow Install, build, and run so you can run incan.

No-install fallback

If you did not run make install, you can still run the incan binary directly:

  • from the repository root:
./target/release/incan ...
  • or via an absolute path (from anywhere):
/absolute/path/to/incan run path/to/file.incn

Simple multi-file project

Recommended structure:

myproject/
├── main.incn
├── models.incn
└── utils.incn

Example imports:

from models import User
import utils::format_currency

Nested projects

Recommended structure:

myproject/
└── src/
    ├── main.incn
    ├── db/
    │   └── models.incn
    └── shared/
        └── utils.incn

Example imports:

from db.models import User
import shared::utils::format_date

How module discovery works (practical view)

When you import a local module, the compiler:

  1. Resolves the path (handling ., .., super, crate)
  2. Looks for the .incn file (or mod.incn for directories)
  3. Parses and type-checks that file
  4. Makes its types and functions available in your importing file

Examples from the repo

  • Multi-file example: examples/advanced/multifile/

Run:

incan run examples/advanced/multifile/main.incn
  • Nested project example: examples/advanced/nested_project/

Run:

incan run examples/advanced/nested_project/src/main.incn

If you prefer browsing first, see the examples directory on GitHub: https://github.com/dannys-code-corner/incan/tree/main/examples.

Share module-owned state across files

If a module needs to export live runtime state, use pub static:

This example shares live runtime state across module boundaries with pub static:

counters.incn
pub static hits: int = 0

pub def record_hit() -> None:
    hits += 1
main.incn
from counters import hits, record_hit

def main() -> None:
    record_hit()
    record_hit()
    println(hits)

This prints 2.

For the full walkthrough, see: Module state (how-to).