MetaScript modules use ES-module syntax. Every .ms / .cms / .jms
/ .wms / .ts file is a module; imports resolve by path with
per-target extension priority. See Code split
for how backend-specific extensions pick the right file per
--target.
Exports
// Named exports
export const PI = 3.14159;
export function add(a: number, b: number): number {
return a + b;
}
export class Calculator {}
// Default export
export default class App {}
// Re-exports
export { foo, bar } from "./other";
export * from "./utils";
export * as utils from "./utils";Imports
// Named imports — extension inferred (.ms / .cms / .jms / .wms / .ts)
import { foo, bar } from "./module";
// Default import
import App from "./app";
// Namespace import
import * as utils from "./utils";
// Combined
import App, { helper } from "./app";
// Type-only import (erased at compile time)
import type { User } from "./types";
// Dynamic import
const module = await import("./dynamic");
// Explicit .ts (still resolves)
import { parse } from "./parser.ts";
// C headers — .h extension required explicitly
import { sqlite3 } from "sqlite3.h";Resolution order
The compiler picks per-target based on --target:
| Target | Candidate order |
|---|---|
--target=c | .cms → .ms → .ts |
--target=js | .jms → .ms → .ts |
--target=c --os=wasm | .wms → .cms → .ms → .ts |
Plain .ms / .ts are universal fallbacks — start everything in
.ms, split into .cms / .jms only when a module needs different
code per target. Details and patterns: Code split.
See also
- Code split — per-module backend selection
- Declarations — what can be exported
- Types —
import typeusage