Skip to content

Modules & Imports

In Flame, every source file (.fm) acts as an isolated module. By default, declarations are private to the file unless explicitly marked with export.


Use export on functions, constants, structs, or annotations:

math_utils.fm
export fn add(a: Int, b: Int) -> Int {
return a + b
}
export const PI: Float = 3.14159
// Private helper (cannot be accessed from outside)
fn internal_helper() {
print("Private computation")
}

Bare Module Imports vs. Quoted Resource Imports

Section titled “Bare Module Imports vs. Quoted Resource Imports”

Flame makes a clear, foundational distinction between module resolution and external resource resolution:

// 1. Bare Imports: Flame packages, standard library, and module namespaces
import std.web
import std.fs
import math_utils
import flamer
// 2. Quoted Imports: External files, data resources, scripts, and stylesheets
import "data.json" as data
import "config.txt" as config
import "playground.js" as scrypt
import "theme.css" as theme
Import Syntax Resolution Engine Target Types Typical Use Cases
Bare Import (import name) Flame Module / Package System .fm source modules, std.*, native crates, downloaded packages Business logic, standard libraries, traits, structs, and functions
Quoted Import (import "path" as alias) File System / Resource Engine .toml, .json, .fmi, .txt, .js, .css, .html Configurations, structured datasets, metadata, stylesheets, client scripts

When imported by bare identifier name, the module creates a namespace from another Flame source file or standard library module:

main.fm
import math_utils
import std.fmt
fn main() {
let result = math_utils.add(10, 20)
print($"Result: {result}, PI: {math_utils.PI}")
}

Resource imports are a universal language feature in Flame, available for every kind of application:

  • CLI tools & daemons: Embed static templates, help texts, or seed schemas without packaging extra directories.
  • Backend servers & microservices: Load configuration files (flame.toml, .env) and data schemas (.json, .fmi) instantly with zero disk IO overhead.
  • Desktop applications: Access bundled assets directly from the filesystem.
  • Web applications (@Web): Seamlessly bundle stylesheets (.css) and client scripts (.js).

Quoted imports support direct filesystem paths, including relative indicators:

  • ./file.ext: Resolves relative to the directory containing the current source file.
  • ../file.ext: Walks up the directory tree relative to the current file (ideal for tests/ importing the project root flame.toml or shared fixtures).
  • file.ext: Searches the current folder and automatically walks up project folders (src/, public/, assets/, static/, root).
// Importing from parent directories or sibling folders
import "../flame.toml" as config
import "./assets/seed.json" as seed
import "../meta.fmi" as meta

1. Data Files & Array Indexing (import "data.json")

Section titled “1. Data Files & Array Indexing (import "data.json")”

Importing a .json file automatically parses structured data into accessible Flame objects and tuples at compile time and runtime:

data.json
{
"appName": "Flame Studio",
"version": "0.6.0",
"maxConnections": 1000,
"features": ["reactive-dom", "wasm-compute", "hot-reload"]
}
main.fm
import "data.json" as data
fn main() {
// Access JSON properties directly without manual fs.read or deserialization!
println($"Launching {data.appName} v{data.version}")
println($"Connection limit: {data.maxConnections}")
println($"First feature: {data.features[0]}")
}

When a JSON file begins with a root array [ ... ], Flame represents it as an indexable collection of objects. You can index by integer (data[0]) and directly access fields by dot (data[0].id) or string key (data[0]["id"]):

users.json
[
{ "id": 1, "name": "Alice", "role": "admin" },
{ "id": 2, "name": "Bob", "role": "developer" }
]
users_test.fm
import "users.json" as users
fn main() {
let first_user = users[0]
println($"First user: {first_user.name} (#{users[0]["id"]})")
println($"Second user: {users[1].name}")
}

2. TOML Configuration Files (import "flame.toml")

Section titled “2. TOML Configuration Files (import "flame.toml")”

Flame natively supports importing TOML configuration files—including flame.toml or custom configuration profiles—with high-speed native parsing:

flame.toml
[package]
name = "my_app"
version = "0.6.0"
tags = ["fast", "reactive"]
[database]
host = "127.0.0.1"
port = 5432
main.fm
import "flame.toml" as config
fn main() {
// Tables and nested properties are accessible via standard dot syntax:
println($"App: {config.package.name} v{config.package.version}")
println($"Primary Tag: {config.package.tags[0]}")
println($"Database: {config.database.host}:{config.database.port}")
}

In @Web builds, TOML configurations are automatically serialized into the client resource bundle so frontend components can inspect build properties and application settings seamlessly.


3. Flame Metadata Interface (import "*.fmi")

Section titled “3. Flame Metadata Interface (import "*.fmi")”

.fmi (Flame Metadata Interface) files are JSON-formatted metadata manifests used for component declarations, plugin contracts, and package interfaces.

Flame treats .fmi files with the same first-class support as JSON:

// component.fmi
{
"name": "DataGrid",
"version": "1.0.0",
"inputs": ["columns", "rows"]
}
import "component.fmi" as meta
fn main() {
println($"Component: {meta.name} (v{meta.version})")
println($"Input 0: {meta.inputs[0]}")
}

4. Static Text & Configuration Files (import "config.txt")

Section titled “4. Static Text & Configuration Files (import "config.txt")”

Text files (.txt, .text, .md) are imported as native String values:

import "motd.txt" as banner
import "config.env" as envConfig
fn main() {
println(banner)
println($"Config payload length: {envConfig.len()} bytes")
}

5. External JavaScript Modules (import "app.js")

Section titled “5. External JavaScript Modules (import "app.js")”

When developing web applications with @Web or integrating with browser environments, you often have existing JavaScript libraries, DOM utilities, or legacy scripts. Flame allows you to import JavaScript files directly:

playground.js
export function loadExample(name) {
const editor = document.getElementById("code");
if (editor) {
editor.value = "// Loaded: " + name;
}
}
export function clearEditor() {
const editor = document.getElementById("code");
if (editor) editor.value = "";
}
main.fm
import std.web
import "playground.js" as scrypt
fn handleSelect(e: Unknown) {
let selected = e.target.value
// Directly call the external JavaScript function!
scrypt.loadExample(selected)
}
fn handleReset(e: Unknown) {
scrypt.clearEditor()
}

What Flame Provides for JavaScript Imports:

Section titled “What Flame Provides for JavaScript Imports:”
  • Intelligent Signature Inspection: Flame scans exported JS functions (export function name(args) or function name(args)) and provides autocomplete for member functions.
  • Unified IDE Experience: Hovering over scrypt.loadExample reveals the signature (fn loadExample(name: Unknown) -> Unknown) and notes External JavaScript function in playground.js.
  • Go-to-Definition: Running Go-to-Definition on loadExample or scrypt jumps straight to the exact line in your .js file.
  • Flexible Argument Passing: Dynamic external JS calls support optional arguments and JavaScript conventions without strict static type mismatches.

6. External Stylesheets (import "theme.css")

Section titled “6. External Stylesheets (import "theme.css")”

CSS files can be imported and bound to aliases to pass directly to @Web configurations:

import "theme.css" as theme
import "style.css" as style
@Web(title: "My App", css: [theme, style])
fn main() {
// ...
}

If a folder contains multiple .fm files, you can import the entire folder as a single namespace. To do this, every .fm file in that folder must begin with a package declaration.

When imported, Flame will scan all .fm files in the folder and aggregate all exported functions, structs, and annotations into a single module namespace.

utils/math.fm
package utils
export fn add(a: Int, b: Int) -> Int {
return a + b
}
utils/string.fm
package utils
@Docs("Reverses a string")
export fn reverse(s: String) -> String {
// ...
}

You can then import the utils folder and access symbols from both files seamlessly:

main.fm
import utils
fn main() {
let sum = utils.add(10, 20)
let rev = utils.reverse("hello")
}

In Flame projects, the top-level src/ directory is implicitly treated as the main package. If you are writing tests inside the tests/ directory (or other folders outside of src/), you can import everything exported from your src/ directory using:

import main
@Test
fn test_something() {
// Access exported symbols from src/ using main.*
let result = main.some_exported_function()
}

You do not need to explicitly declare package main in your src/ files. When you write import main, Flame will automatically aggregate all exported symbols across the .fm files in your src/ folder.

Flame’s language server fully supports folder-based imports, meaning custom @Docs and autocomplete suggestions will work accurately across all files aggregated in the namespace.


Custom annotations exported from a module are automatically brought into scope without requiring namespace qualification:

orm.fm
export annotation Entity(table: String) -> String {
return table
}
// models.fm
import orm
@Entity("users")
struct User {
id: Int,
name: String
}

Flame allows you to publish modules as reusable packages that can be imported by other projects.

To create a standalone Flame package, update your flame.toml to specify type = "pkg" (or type = "lib"). Packages do not require a main.fm entry point, they simply act as a collection of exported components inside their src/ directory.

[package]
name = "flamer"
version = "0.1.0"
type = "pkg"

You can depend on external Flame packages by adding them to the [dependencies] block of your flame.toml.

[dependencies]
flamer = "https://github.com/shoya-129/flamer"

Run fmp install to resolve and cache dependencies into .flame/pkg/:

bash
fmp install

During fmp build, Blaze performs dependency analysis and constructs an application-specific native runtime containing only the packages and native components your application actually imports and uses.