Skip to content

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.

MechanismSyntaxPurposeRuntime Cost
Nativeuse module.nameImport Janus modulesZero
Zig Bridgeuse zig "path.zig"Import an explicit Zig bridge module or generated wrapperZero
C Graftgraft c "header.h"Import C librariesFFI boundary

The use statement is the Janus-native module import mechanism. It creates a namespace binding named after the last path component.

// Import a module — binds the name "http" to the module's exports
use std.net.http
// Use the imported module
const response = http.get("https://api.example.com/data")

The compiler resolves module paths by:

  1. Joining identifiers with / (e.g., std.net.httpstd/net/http.jan)
  2. Appending .jan extension
  3. Searching relative to the source file’s directory
  4. Falling back to Janus stdlib root

When you need a different name or want to avoid conflicts:

// Rename on import
use std.crypto.blake3 as hash
use std.io.file as fs
// Use the alias
const digest = hash.digest(data)
const content = fs.read("config.txt")

Modules can re-export other modules to create convenience indexes:

// std/std.jan — Standard Library Index
pub use std.core as core
pub use std.io as io
pub use std.net.http as http
// Users can now:
// use std.http // Instead of use std.net.http

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.

// Explicit bridge modules
use zig "std/bridge/process_bridge.zig"
use zig "std/bridge/json_bridge.zig"
// Local project bridges are also valid
use zig "bridge/net_bridge.zig"

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 zig or graft c)
  • Is typed (Zig/C types map to Janus types at compile time)
  • Is replaceable (swap the graft without changing call sites)

For C libraries, use the graft c syntax with explicit aliasing and optional linking.

// Import a C header with an alias
graft c "oqs/oqs.h" as oqs
graft c "argon2.h" as argon2
// Use via the alias
const rc = oqs.OQS_SIG_ml_dsa_65_verify(...)
// Specify the library to link against
graft c "oqs/oqs.h" as oqs link "oqs"
graft c "argon2.h" as argon2 link "argon2"
graft c "sodium.h" as sodium link "sodium"

C code integration follows three principles:

  1. Explicit: The graft c keyword makes foreign code obvious
  2. Contained: All FFI calls go through the named alias
  3. Replaceable: Swap implementations without changing consuming code
// ❌ WRONG — Don't mix mechanisms
const std = @import("std") // Zig syntax, not Janus
import * as http from "http" // JavaScript syntax
#include <stdio.h> // C preprocessor syntax
// ✅ CORRECT — Janus-native imports
use std.io
use zig "std/bridge/http_bridge.zig"
graft c "stdio.h" as c_stdio
// Standard library
use std.core
use std.io.file
use std.net.http
use std.crypto.blake3
// Local project modules
use myapp.models
use myapp.controllers.auth
// Approved bridge modules
use zig "std/bridge/process_bridge.zig"
use zig "std/bridge/http_bridge.zig"
// Local Zig files (relative to source file)
use zig "../native/optimized.zig"
use zig "bridge/wasm.zig"
// System headers
graft c "stdio.h" as c_stdio
graft c "stdlib.h" as c_stdlib
// Local headers
graft c "../vendor/custom.h" as vendor
graft c "native/specialized.h" as native

Use native Janus modules when available:

// ✅ Good — Native Janus
use std.crypto.blake3
// ⚠️ Only if needed — explicit bridge module
use zig "std/bridge/json_bridge.zig"
// ✅ Good — Clear intent
use std.crypto.blake3 as hasher
use std.io.file as fs
// ❌ Avoid — Cryptic aliases
use std.crypto.blake3 as b3
use std.io.file as f
// Standard library imports
use std.core
use std.io
use std.net.http
// Explicit bridge imports
use zig "std/bridge/process_bridge.zig"
// C library imports
graft c "oqs/oqs.h" as oqs
// Local project imports
use myapp.config
use myapp.models
//! 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 system
pub func initContext() ssl.SSL_CTX {
// ...
}

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.

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)
  1. Language Identity: Janus is distinct from Zig; mixing syntax creates confusion
  2. Future-Proofing: The @ character is reserved for future inline documentation (e.g., @param, @deprecated)
  3. Consistency: A single, clear import mechanism for each use case