Imports guide
Split your app into multiple .ny files and share functions, types, and constants
with import "path.ny" or selective import { name } from "path.ny" — then build from the project root.
How imports work
When you run nyra run . or nyra build ., the compiler starts at
main.ny and recursively loads every import it finds. Definitions
are merged into one program (like compiling one big file).
Whole-module imports bring all pub symbols; selective imports bring only the names you list
(plus same-file helpers those names need).
main.ny
import "src/util.ny" ──► all pub from util.ny
import { add } from "math.ny" ──► only add (+ its helpers)
import "models/user.ny" as u ──► u::… / u__…
│
▼
Merged program → typecheck → borrow → LLVM
nyra run main.ny compiles only that file and does not follow imports.
Use nyra run . from the directory that contains main.ny.
Path rules
| Import string | Resolved from |
|---|---|
"src/foo.ny" | Relative to the file containing the import |
"types.ny" | Same directory as the importing file |
"stdlib/vec.ny" | $NYRA_HOME/share/stdlib/, install tree, or repo stdlib/ — works from any project depth |
"std/json/mod" | Alias for stdlib/json/mod.ny (extension optional) |
"stdlib/prelude.ny" | Bundle: vec, map, strings/ops, log |
"pkg/ny-sqlite" | .nyra/cache/ny-sqlite/ after nyrapkg install ny-sqlite@^0.1.0 (see nyrapkg) |
Import forms
| Syntax | What merges | Use when |
|---|---|---|
import "math.ny" |
All pub symbols from the file |
Small modules / you need most of the API |
import "math.ny" as m |
All pub symbols as m::name / m__name |
Avoid name clashes; keep a module prefix |
import { add, mul } from "math.ny" |
Only those pub names (+ same-file helpers they call) |
Lean builds — prefer for large files |
import { greet as hi } from "helpers.ny" |
One pub symbol, renamed locally |
Clearer call-site names |
Visibility: omit modifier or use pub to export; priv stays internal.
Selective imports of a priv name fail with E039.
Selective imports
Prefer import { … } from "…" when you only need a few symbols. Even a single name
still uses braces: import { add } from "math.ny".
src/math.ny
pub fn add(a, b) {
return a + b
}
pub fn mul(a, b) {
return a * b
}
pub fn unused_export() {
return 0
}src/math.ny
pub fn add(a, b) -> i32 {
return a + b
}
pub fn mul(a, b) -> i32 {
return a * b
}
pub fn unused_export() -> i32 {
return 0
}main.ny
import { add, mul } from "src/math.ny"
fn main() {
print(add(10, 20)) // 30
print(mul(3, 7)) // 21
// unused_export is not merged
}main.ny
import { add, mul } from "src/math.ny"
fn main() -> void {
print(add(10, 20)) // 30
print(mul(3, 7)) // 21
// unused_export is not merged
}Rename with as
import { greet as hi } from "src/helpers.ny"
fn main() {
print(hi("nyra"))
}import { greet as hi } from "src/helpers.ny"
fn main() -> void {
print(hi("nyra"))
}priv),
the compiler pulls that dependency into the merge automatically. Unrelated pub
exports stay out.
Importing functions
Define functions in a module file; call them from main.ny after importing (whole module or selective).
src/math.ny
fn double(x){
return x * 2
}
fn triple(x) {
return x * 3
}src/math.ny
fn double(x: i32){
return x * 2
}
fn triple(x: i32) -> i32 {
return x * 3
}main.ny
import "src/math.ny"
fn main() {
print(double(5)) // 10
print(triple(5)) // 15
}main.ny
import "src/math.ny"
fn main() -> void {
print(double(5)) // 10
print(triple(5)) // 15
}cd myapp
nyra run .
There is no per-item export keyword — top-level items default to pub. Mark helpers priv so whole-module imports skip them. Prefer selective import { … } when you only need a few names (see selective imports).
Importing structs
Structs live in one file; other files import that file to use the type and its fields.
models/point.ny
struct Point {
x: i32
y: i32
}
fn origin() {
return Point { x: 0, y: 0 }
}models/point.ny
struct Point {
x: i32
y: i32
}
fn origin() -> Point {
return Point { x: 0, y: 0 }
}main.ny
import "models/point.ny"
fn main() {
let p = origin()
print(p.x)
print(p.y)
}main.ny
import "models/point.ny"
fn main() -> void {
let p = origin()
print(p.x)
print(p.y)
}Split types and operations (calculator pattern)
Real project in the Nyra repo: examples/projects/calculator/
types.nystruct Calculator {
value: i32
}
ops.ny
import "types.ny"
fn add_calc(c, n) {
return Calculator { value: c.value + n }
}ops.ny
import "types.ny"
fn add_calc(c: Calculator, n: i32) -> Calculator {
return Calculator { value: c.value + n }
}main.ny
import "types.ny"
import "ops.ny"
fn main() {
let c = Calculator { value: 0 }
let c2 = add_calc(c, 10)
print(c2.value)
}main.ny
import "types.ny"
import "ops.ny"
fn main() -> void {
let c = Calculator { value: 0 }
let c2 = add_calc(c, 10)
print(c2.value)
}Importing enums
Enum definitions merge like functions. Use Type.Variant syntax after import.
colors.ny
enum Status {
Ok
Err
}
fn is_ok(s) {
return match s {
Status.Ok => true
Status.Err => false
}
}colors.ny
enum Status {
Ok
Err
}
fn is_ok(s: Status) -> i32 {
return match s {
Status.Ok => true
Status.Err => false
}
}main.ny
import "colors.ny"
fn main() {
let s = Status.Ok
print(is_ok(s))
}main.ny
import "colors.ny"
fn main() -> void {
let s = Status.Ok
print(is_ok(s))
}Importing constants
Top-level const bindings in imported files are merged into the program.
config.nyconst MAX_USERS = 100
const APP_NAME = "MyApp"config.nyconst MAX_USERS = 100
const APP_NAME = "MyApp"main.ny
import "config.ny"
fn main() {
print(MAX_USERS)
print(APP_NAME)
}main.ny
import "config.ny"
fn main() -> void {
print(MAX_USERS)
print(APP_NAME)
}Standard library files
Runtime helpers are declared in stdlib/*.ny and backed by the Nyra C runtime. Builtins print, time_start/time_end, mem_start/mem_end need no import.
main.ny
import "stdlib/fs.ny"
fn main() {
let s = read_file("data.txt")
print(s)
// compiler auto-drops s — no free needed
}main.ny
import "stdlib/fs.ny"
fn main() -> void {
let s = read_file("data.txt")
print(s)
// compiler auto-drops s — no free needed
}Use short paths — no ../../../stdlib/... from examples:
import "stdlib/prelude.ny"
import "stdlib/async.ny"
import "stdlib/json/mod.ny"import "stdlib/prelude.ny"
import "stdlib/async.ny"
import "stdlib/json/mod.ny"Full function list: Standard library. Refresh installed stdlib with ./scripts/updateLang.sh after upgrades.
Rules & pitfalls
| Topic | Guidance |
|---|---|
| Duplicate names | Two imported files must not define the same fn / struct name; merge keeps the first. Use as alias or selective rename |
fn main | Only one entry — keep it in main.ny |
| Import cycles | Avoid a.ny imports b.ny and b.ny imports a.ny |
| Visibility | Default pub; priv is hidden from importers. Selective import of priv → E039 |
| Missing selective name | import { missing } from "…" → E039 (lists available pub symbols) |
| Single-name selective | Still needs braces: import { add } from "math.ny" |
| Variables | let inside functions is local — not “exported”. Share data via const, functions, or structs |
| Mutable globals | Not supported as imports; use functions that return state |
| Run command | nyra run . not nyra run main.ny for multi-file |
| Unused import | W002 — remove the line or run nyra pkg prune |
nyra run .
nyra build .
nyra check .
nyra run main.ny
# imports ignored
More runnable snippets: Built-in methods.