Modules and Packages
js/modules-and-packages.md
Fino uses ES modules for application code, built-in runtime APIs, and installed
packages. The module loader understands local specifiers, public fino:*
built-ins, selected web-style globals, and package mappings generated by
fino install.
Local Modules
Use relative imports for files in your project:
import { loadConfig } from './config.ts';
import { createServer } from './server.ts';
Prefer explicit extensions in application code. Fino's own runtime modules use
.ts files and the docs link directly to those source modules.
Local file:// URLs are accepted for local filesystem paths, including
percent-encoded path characters such as spaces. Malformed percent escapes and
non-local file://host/... URLs are rejected. Directory imports are not
expanded to index files; import the file you want directly.
Built-In Modules
Use fino:* specifiers for runtime APIs:
import { serveHttp } from 'fino:net/http/server';
import { Database } from 'fino:database/sqlite';
import { parse as parseCsv } from 'fino:format/csv';
import { Watcher } from 'fino:file/watch';
The shape of the specifier mirrors the public module location under js/.
Examples:
js/net/http/server.tsis imported asfino:net/http/server.js/database/sqlite.tsis imported asfino:database/sqlite.js/realm/index.tsis imported asfino:realm.
Only import documented public modules from applications. Other runtime specifier forms are not part of the supported application API.
Public API Boundaries
Application code should depend on:
- local project modules,
- web-standard globals and objects provided by the runtime,
fino:*built-ins,- installed npm packages.
Application code should avoid:
- unsupported runtime module specifiers,
- deep imports into
.fino/packages, - generated files inside
docs/, - relying on undocumented side effects of runtime startup.
That boundary keeps code portable across runtime changes and lets generated docs represent the supported API surface.
Because capabilities arrive through imports, this boundary is also a security surface: child realms can be restricted to a narrow set of importable modules through import rules. See the runtime model and Import Capabilities.
Installed Packages
Initialize a package file:
fino init --yes
Install dependencies:
fino install yaml semver
Fino installs package contents under .fino/packages and writes
.fino/package-map.json. The package map tells the loader which files satisfy
bare package imports and exported subpaths.
After installation, import packages by their package names:
import semver from 'semver';
console.log(semver.satisfies('1.4.2', '^1.0.0'));
Run fino install again after changing dependencies in package.json.
The package map is the supported package-resolution surface. Fino does not walk
node_modules or evaluate package.json files at import time; the installer
expands npm metadata into the map when packages are installed, and the loader
resolves bare imports from the map alone. The package map is also the current
reproducibility artifact: commit it when your project expects reproducible
bare-import resolution.
JSON files are imported as modules with a default export. Fino currently accepts JSON imports with or without Node-style import attributes; strict JSON import-attribute enforcement is not part of this release baseline.
Current Installer Limits
fino install resolves packages from FINO_NPM_REGISTRY when it is set, or
from the public npm registry by default. Current limits to be aware of:
- No separate lockfile yet; the committed package map plays that role.
- No persistent package cache, offline mode, proxy configuration, or registry authentication; packument caching is in-memory per install run.
- Package lifecycle scripts (
preinstall,install,postinstall) are not run. - Optional dependencies that fail to resolve or install are skipped with a warning; peer dependencies are reported as warnings and not installed.
- Package
exportsentries are expanded into concrete package-map entrypoints (strings, arrays,import/defaultcondition objects, simple*patterns, andmodule/mainfallbacks). Packageimportsentries and#specifierimports are not supported; use relative imports or published export subpaths. - Downloaded tarballs are verified when registry metadata provides integrity
data and the runtime has OpenSSL support:
dist.integritySRI is preferred, with fallback to the legacy SHA-1dist.shasum; a malformed SRI with no shasum fails the install. Without OpenSSL, verification is skipped because the digest backend is unavailable.
Full npm resolver parity is outside this baseline.
Synthetic Modules
SyntheticModule installs a same-realm virtual module under a bare specifier.
Installing the same SyntheticModule twice throws, and installing a different
synthetic module at an already-installed specifier also throws. After a module
is uninstalled, that specifier can be installed again and subsequent imports
see the new exports.