Import System
Janus provides a clear, hierarchical import system that distinguishes between native Janus modules, Zig libraries, and C libraries. This guide covers all three mechanisms and explains when to use each.
The Three Import Mechanisms
Section titled “The Three Import Mechanisms”| Mechanism | Syntax | Purpose | Runtime Cost |
|---|---|---|---|
| Native | use module.name | Import Janus modules | Zero |
| Zig Bridge | use zig "path.zig" | Import an explicit Zig bridge module or generated wrapper | Zero |
| C Graft | graft c "header.h" | Import C libraries | FFI boundary |
Native Imports: use
Section titled “Native Imports: use”The use statement is the Janus-native module import mechanism. It creates a namespace binding named after the last path component.
Basic Usage
Section titled “Basic Usage”// Import a module — binds the name "http" to the module's exportsuse std.net.http
// Use the imported moduleconst response = http.get("https://api.example.com/data")Resolution Algorithm
Section titled “Resolution Algorithm”The compiler resolves module paths by:
- Joining identifiers with
/(e.g.,std.net.http→std/net/http.jan) - Appending
.janextension - Searching relative to the source file’s directory
- Falling back to Janus stdlib root
Aliases with as
Section titled “Aliases with as”When you need a different name or want to avoid conflicts:
// Rename on importuse std.crypto.blake3 as hashuse std.io.file as fs
// Use the aliasconst digest = hash.digest(data)const content = fs.read("config.txt")Module identity and same-name files
Section titled “Module identity and same-name files”An import alias is a local name for a resolved module. The module contract keeps functions in distinct files separate even when their filenames and function names match. Importing one resolved file through several aliases or through a shared dependency must continue to refer to that same module.
Development caveat, September 14, 2026: the compiler’s internal function
names used only the filename stem, which could conflate distinct files such
as context/state.jan and matchmaker/state.jan. Changing their local aliases
did not prevent that collision. A correction that uses a per-compilation
module identity passes focused native regressions in local commit 1b7725fa.
The subsequent scalar-type corrections are also locally verified. A rebuilt
Graf executable runs, but its native Git consumer fixture fails; consumer
qualification remains pending. See the
module identity development note
for the affected scope and validation status.
Public Re-exports
Section titled “Public Re-exports”Modules can re-export other modules to create convenience indexes:
// std/std.jan — Standard Library Indexpub use std.core as corepub use std.io as iopub use std.net.http as http
// Users can now:// use std.http // Instead of use std.net.httpExplicit Zig Bridges: use zig
Section titled “Explicit Zig Bridges: use zig”Use use zig only when you are crossing an intentional Janus/Zig boundary.
That usually means one of these:
- an approved bridge module under
std/bridge - a local project bridge file
- a compiler-generated wrapper
Normal application .jan files should prefer Janus modules such as use std.crypto.blake3.
Importing Approved Bridge Modules
Section titled “Importing Approved Bridge Modules”// Explicit bridge modulesuse zig "std/sys/linux/process.zig"use zig "std/bridge/mem_raw_bridge.zig"
// Local project bridges are also validuse zig "bridge/net_bridge.zig"Why “Grafting”?
Section titled “Why “Grafting”?”The term “graft” reflects the Janus philosophy: foreign code is explicitly marked, contained, and can be replaced. Unlike opaque FFI bindings, grafted code:
- Is visible in your source (explicit
use zigorgraft c) - Is typed (Zig/C types map to Janus types at compile time)
- Is replaceable (swap the graft without changing call sites)
C Grafting: graft c
Section titled “C Grafting: graft c”For C libraries, use the graft c syntax with explicit aliasing and optional linking.
Basic C Import
Section titled “Basic C Import”// Import a C header with an aliasgraft c "oqs/oqs.h" as oqsgraft c "argon2.h" as argon2
// Use via the aliasconst rc = oqs.OQS_SIG_ml_dsa_65_verify(...)With Link Flags
Section titled “With Link Flags”// Specify the library to link againstgraft c "oqs/oqs.h" as oqs link "oqs"graft c "argon2.h" as argon2 link "argon2"graft c "sodium.h" as sodium link "sodium"The Grafting Doctrine (GD-1)
Section titled “The Grafting Doctrine (GD-1)”C code integration follows three principles:
- Explicit: The
graft ckeyword makes foreign code obvious - Contained: All FFI calls go through the named alias
- Replaceable: Swap implementations without changing consuming code
Signature Contract
Section titled “Signature Contract”Since a2780174 on unstable (PR #34, 2026-10-11, not yet in a tagged
release), grafted C signatures follow a fail-closed contract. It applies to
graft c headers and to extern declarations read through use zig and
graft zig:
| Declaration | Result |
|---|---|
int abs(int); (unnamed parameters) | Called like int abs(int value);; type and position preserved |
restrict pointer parameters | Keep their pointer type |
int printf(const char *, ...); | Declaration accepted; every call fails with E2413 |
| A variadic function pointer in a parameter or return type | Calls fail with E2413 |
| Fixed-signature functions and function pointers | Usable as before |
Call a variadic C function through a fixed C-ABI adapter instead. The grafting reference shows the diagnostics and a working adapter.
Comparison Table
Section titled “Comparison Table”// ❌ WRONG — Don't mix mechanismsconst std = @import("std") // Zig syntax, not Janusimport * as http from "http" // JavaScript syntax#include <stdio.h> // C preprocessor syntax
// ✅ CORRECT — Janus-native importsuse std.iouse zig "std/bridge/http_bridge.zig"graft c "stdio.h" as c_stdioModule Path Conventions
Section titled “Module Path Conventions”Janus Modules
Section titled “Janus Modules”// Standard libraryuse std.coreuse std.io.fileuse std.net.httpuse std.crypto.blake3
// Local project modulesuse myapp.modelsuse myapp.controllers.authZig Paths
Section titled “Zig Paths”// Approved bridge modulesuse zig "std/sys/linux/process.zig"use zig "std/sys/linux/http.zig"
// Local Zig files (relative to source file)use zig "../native/optimized.zig"use zig "bridge/wasm.zig"C Headers
Section titled “C Headers”// System headersgraft c "stdio.h" as c_stdiograft c "stdlib.h" as c_stdlib
// Local headersgraft c "../vendor/custom.h" as vendorgraft c "native/specialized.h" as nativeBest Practices
Section titled “Best Practices”1. Prefer Native Janus
Section titled “1. Prefer Native Janus”Use native Janus modules when available:
// ✅ Good — Native Janususe std.crypto.blake3
// ⚠️ Only if needed — explicit bridge moduleuse zig "std/sys/linux/time.zig"2. Use Descriptive Aliases
Section titled “2. Use Descriptive Aliases”// ✅ Good — Clear intentuse std.crypto.blake3 as hasheruse std.io.file as fs
// ❌ Avoid — Cryptic aliasesuse std.crypto.blake3 as b3use std.io.file as f3. Group Imports
Section titled “3. Group Imports”// Standard library importsuse std.coreuse std.iouse std.net.http
// Explicit bridge importsuse zig "std/sys/linux/process.zig"
// C library importsgraft c "oqs/oqs.h" as oqs
// Local project importsuse myapp.configuse myapp.models4. Document C Grafts
Section titled “4. Document C Grafts”//! TLS implementation using OpenSSL via graft
graft c "openssl/ssl.h" as ssl link "ssl"graft c "openssl/err.h" as ssl_err link "ssl"
/// Initialize SSL context/// Requires: libssl-dev installed on systempub func initContext() ssl.SSL_CTX { // ...}Migration from @import
Section titled “Migration from @import”Prior to version 2026.4.3, some Janus files incorrectly used Zig’s @import syntax. This has been deprecated and removed. Migrations should prefer Janus module paths first and only introduce use zig when the target is an explicit bridge module.
Migration Examples
Section titled “Migration Examples”| Old (Zig syntax) | New (Janus syntax) |
|---|---|
const std = @import("std") | use std |
const core = @import("core.jan") | use std.core as core |
const hash = @import("crypto/blake3.jan") | use std.crypto.blake3 as hash |
const local = @import("../local.jan") | use local (or appropriate module path) |
Why the Change?
Section titled “Why the Change?”- Language Identity: Janus is distinct from Zig; mixing syntax creates confusion
- Future-Proofing: The
@character is reserved for future inline documentation (e.g.,@param,@deprecated) - Consistency: A single, clear import mechanism for each use case
Related Concepts
Section titled “Related Concepts”- Grafting Doctrine — Deep dive into the philosophy and implementation of grafting
- Zig Integration Tutorial — Step-by-step guide to integrating Zig code
- Package Management — How Hinge manages module dependencies
- Language Reference — Complete syntax and semantics