Skip to content

sys ​

ts
import {
  
memoryUsage
,
storageUsage
,
deviceName
,
setDeviceName
,
uptime
,
gc
,
restart
,
exit
,
panic
,
board
,
firmware
,
deviceId
,
resetReason
,
version
,
} from 'mikro/sys'

System-level functions for memory monitoring, timing, garbage collection, device info, and environment variables.

Functions ​

memoryUsage() ​

ts
function memoryUsage(): MemoryUsage

Returns current heap usage.

ts
const 
mem
=
memoryUsage
()
const
free
=
mem
.
heapTotal
-
mem
.
heapUsed
console
.
log
('Free memory: %dKB',
free
/ 1000)

storageUsage() ​

ts
function storageUsage(): {total: number; used: number; free: number} | undefined

Bytes on the app filesystem — the partition an over-the-air build is downloaded and staged onto. Returns undefined when the platform cannot report it.

ts
const 
storage
=
storageUsage
()
if (
storage
)
console
.
log
('Free storage: %dKB',
storage
.
free
/ 1000)

An OTA check-in can report free so the registry withholds builds that would not fit; see the over-the-air updates guide.

uptime() ​

ts
function uptime(): Uptime

Returns time since boot and RTC time.

ts
const {
boot
,
rtc
} =
uptime
()
console
.
log
('Up for %d ms',
boot
)
console
.
log
('RTC: %d ms',
rtc
)
PropertyDescription
bootMilliseconds since last boot (resets on deep sleep)
rtcMilliseconds from RTC clock (survives deep sleep)

gc() ​

ts
function gc(): void

Runs the cycle collector. Not normally needed: QuickJS frees objects as soon as the last reference drops, via reference counting. The cycle collector only reclaims memory held by reference cycles (objects that refer to each other).

restart() ​

ts
function restart(): never

Restarts the device immediately.

getWakeupCause() ​

ts
function getWakeupCause(): string

Returns why the device booted. Useful for branching logic right after a deep sleep cycle.

ts
const 
cause
=
getWakeupCause
()
console
.
log
('Woke up because: %s',
cause
)

Possible values: 'timer', 'ext0', 'ext1', 'gpio', or 'undefined' (cold boot or unknown).

resetReason ​

ts
const resetReason: ResetReason

Why the device last reset, determined once at boot. Pairs with getWakeupCause(), which reports why the device woke from deep sleep.

ts
if (
resetReason
=== 'panic') {
console
.
log
('Recovering from a crash')
}

On ESP32 this maps the ESP-IDF reset reason: a clean restart() reports 'software', while an unhandled crash reports 'panic'. On host/Node builds there is no chip-reset concept, so it is always 'unknown'.

Possible values: 'power-on', 'software', 'panic', 'watchdog', 'interrupt-watchdog', 'task-watchdog', 'brownout', 'deep-sleep', 'external', 'sdio', 'usb', 'jtag', 'efuse', 'power-glitch', 'cpu-lockup', or 'unknown'.

'task-watchdog' means the hardware task watchdog reset the device because native code below the JavaScript layer stopped responding. The JavaScript-level watchdogs do not produce it: they restart through the normal panic path, so the next boot reports 'software', or 'deep-sleep' when onPanic deep-sleeps the device.

exit(exitCode?) ​

ts
function exit(exitCode?: number): never

Stops the current program. On device, this returns to the REPL.

panic(message) ​

ts
function panic(message: string): never

Immediately crashes with an error message. Use for truly unrecoverable situations.

board ​

ts
const board: BoardInfo

Board and hardware info, evaluated once at startup.

ts
console
.
log
('%s - %d core(s)',
board
.
chip
,
board
.
cores
)
console
.
log
('Features: %s',
board
.
features
.
join
(', '))
console
.
log
('Flash: %dMB',
board
.
flash
/ 1024 / 1024)
PropertyDescription
nameThe board, as its firmware project names it (for example "@acme/devboard"), or "<chip>-generic" for the generic firmware (for example "esp32c6-generic"). A board that runs the generic firmware reports its own name, which mikro flash writes in
chipChip target (for example "esp32c6") or "host"
coresNumber of CPU cores
revisionSilicon revision (major * 100 + minor on ESP32, 0 on host)
featuresSupported features (for example ["wifi", "ble"])
flashFlash size in bytes (0 on host)
psramPSRAM size in bytes (0 if unavailable)

wifi, ble and bt appear only when the chip supports them and the matching stack was compiled into the firmware, so features answers whether the module behind a radio will work. ieee802154 reports silicon alone.

firmware ​

ts
const firmware: FirmwareInfo

Firmware build identifiers. Useful for debugging and detecting firmware changes.

ts
console
.
log
('Build: %s',
firmware
.
hash
)
console
.
log
('Date: %s',
firmware
.
date
)
PropertyDescription
nameThe firmware build: "<chip>-generic" for the generic firmware, or the board it was built for (for example "@acme/devboard")
hashELF SHA256 hash on ESP32, "dev" on host
dateBuild date and time
idfVersionESP-IDF version string, undefined on host
bytecodeVersionQuickJS bytecode version this firmware loads

bytecodeVersion is what an app build has to match to run on this device: bytecode is not portable across QuickJS versions, so a build compiled for a different one cannot be loaded. Send it with version on an OTA check-in so the registry only offers builds this device can actually run. See the Over-the-air Updates guide.

version ​

ts
const version: string

The mikrojs firmware version, baked in at build time from the workspace package.json (for example "0.1.0"). Always a valid semver string. Falls back to "0.0.0-dev" if the build did not set MIK_FW_VERSION.

ts
console
.
log
('mikrojs %s',
version
)

deviceId ​

ts
const deviceId: string

A unique device identifier encoded as Crockford's Base32 (10 lowercase characters, no special symbols).

ts
console
.
log
('Device: %s',
deviceId
)
// e.g. "5dsgr8kwev"

On ESP32, derived from the chip's base MAC address. The encoding is lossless: decoding the 10 characters yields the original 6 MAC bytes. On host/Node builds, derived from the hostname (stable across restarts on the same machine).

deviceName() ​

ts
function deviceName(): {rev: number; name?: string}

The name the device carries for itself, set with mikro name or at enrollment, together with the revision that orders renames. Revision 0 with no name means the device has never been named — fall back to deviceId.

ts
const {
name
} =
deviceName
()
console
.
log
('I am %s',
name
??
deviceId
)

setDeviceName(value) ​

ts
function setDeviceName(value: {rev: number; name?: string}): void

Stores a name pair, replacing any previous one. This is an unconditional write; it does not compare revisions. Mainly for adopting a name handed down by a registry at check-in. The registry arbitrates: it compares the revision the device reports against its own, and the device stores whatever comes back. Every deliberate rename bumps rev by one, so the two sides converge without needing a clock the device may not have. Omit name to record that the name was cleared. The revision still has to move, or the old name comes back on the next sync.

setSystemTime(timestamp) ​

ts
function setSystemTime(timestamp: number): void
function setSystemTime(date: Date): void

Sets the system clock. Typically called after SNTP sync or with a known timestamp.

Types ​

MemoryUsage ​

ts
interface MemoryUsage {
  heapUsed: number
  heapTotal: number
}

Uptime ​

ts
interface Uptime {
  readonly boot: number // ms since boot
  readonly rtc: number // ms from RTC
}

BoardInfo ​

ts
interface BoardInfo {
  name: string
  chip: string
  cores: number
  revision: number
  features: string[]
  flash: number
  psram: number
}

ResetReason ​

ts
type ResetReason =
  | 'power-on'
  | 'software'
  | 'panic'
  | 'watchdog'
  | 'interrupt-watchdog'
  | 'task-watchdog'
  | 'brownout'
  | 'deep-sleep'
  | 'external'
  | 'sdio'
  | 'usb'
  | 'jtag'
  | 'efuse'
  | 'power-glitch'
  | 'cpu-lockup'
  | 'unknown'

MonotonicTimestamp ​

A timestamp based on uptime that is not affected by NTP adjustments. Useful for measuring elapsed time reliably, and for logging events before the device clock is synced via NTP.

ts
const 
start
=
MonotonicTimestamp
.
now
()
// ... do work ... const
elapsed
=
MonotonicTimestamp
.
now
().
since
(
start
)
console
.
log
('Took %d ms',
elapsed
)

Logging events before NTP sync:

ts
import {
MonotonicTimestamp
} from 'mikro/sys'
const
events
:
Array
<{
ts
:
MonotonicTimestamp
;
msg
: string}> = []
// These timestamps are captured before NTP has synced
events
.
push
({
ts
:
MonotonicTimestamp
.
now
(),
msg
: 'WiFi connected'})
events
.
push
({
ts
:
MonotonicTimestamp
.
now
(),
msg
: 'MQTT broker reached'})
// Later, after NTP sync, convert to wall-clock times. // toDate() returns err('ClockNotSynced') if the resolved time is // before the firmware build date (i.e. the clock hasn't been synced). for (const
event
of
events
) {
const
result
=
event
.
ts
.
wallDate
()
if (
result
.
ok
) {
console
.
log
(`[${
result
.
value
.
toISOString
()}] ${
event
.
msg
}`)
} else {
console
.
log
(`[uptime:${
event
.
ts
.
uptimeMs
}ms] ${
event
.
msg
}`)
} }
MethodDescription
MonotonicTimestamp.now()Create a timestamp at the current moment
.since(other)Milliseconds elapsed since another timestamp
.wallDate()Convert to a Date, or err 'ClockNotSynced' if clock isn't set

Mikro.js is built with AI assistance, code and docs alike. Read the AI disclosure.