N/ NIFT LABS

Experiment 01 / runtime & scripting

One runtime.
Different kinds
of work.

What does Nift cost as a scripting language? Separate startup-sensitive snippets from sustained computation and practical file/data work, then compare idiomatic implementations.

Series 20261015-v4120-final-c14d068 · Nift 4.12.0 final candidate · frozen source revision. Current figures use final audited observations. Earlier reports retain their own dated series; samples are not pooled.

Read the workload first

A language score hides the tradeoffs.

STARTUP

No-op/output mainly expose invocation cost. Tiny snippets are not application throughput.

COMPUTE

Loops, calls, arrays, map/set, Fibonacci and grid BFS exercise interpreter/JIT and collection paths.

FILES + DATA

JSON reads/parsing, record transformation/traversal and recursive files include actual I/O/helper costs.

Absolute latency

Startup and sustained work tell different stories.

Nift’s tiny no-op median was 2.463 ms, while the large arithmetic-loop invocation was 72.592 ms. Read the latter alongside native/JIT peers below: low invocation cost does not establish sustained execution throughput.

All participating languages; fresh-process median ms, 10 measured samples per cell
Workload / sizeniftpythonrubylua54luajitnodebash
sanity/noop / small2.46318.08668.7641.3881.22829.1941.729
sanity/loops / large72.59225.14074.3121.9281.41935.264295.9
sanity/function-calls / large193.729.07975.6753.7311.41935.443518.1
arrays-strings-hash/sort-index / large511.623.05278.73436.89134.92446.026211.8
graphs-trees-search/bfs / large799.496.861121.735.28116.93282.224—
structured-data/json-parse / large182.179.343174.6——66.988—
filesystem/traverse / large25.00530.24872.0587.6497.64148.9288.270

A dash (—) means the implementation was outside scope and deliberately excluded; it is not a zero or a failed measurement. Selected classes are not an overall ranking.

sanity/noop / small. Invocation latency (ms). Zero-based axis.
sanity/noop / small. Zero-based scale. SVG · PNG. Exact values appear in the accompanying tables.
sanity/loops / large. Invocation latency (ms). Logarithmic axis.
sanity/loops / large. Logarithmic scale; bar lengths are not proportional to values. SVG · PNG. Exact values appear in the accompanying tables.
filesystem/traverse / large. Invocation latency (ms). Logarithmic axis.
filesystem/traverse / large. Logarithmic scale; bar lengths are not proportional to values. SVG · PNG. Exact values appear in the accompanying tables.

sanity/noop

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small2.46318.08668.7641.3881.22829.1941.729
large2.38917.87968.2991.3811.18429.2801.607
Retained tails and memory: sanity/noop
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms2.84919.06082.8961.5991.29932.3802.083
small / Minimum ms2.37817.65466.7651.3401.14826.7541.630
small / Maximum ms2.97719.11792.7211.7411.31033.4902.356
small / RSS MiB5.87510.00022.6252.2502.37541.5743.500
large / p95 ms2.51120.45784.4181.6151.22731.0801.994
large / Minimum ms2.12917.41167.0001.2261.09626.8321.580
large / Maximum ms2.53621.94792.4321.7471.22832.0012.191
large / RSS MiB5.75010.00022.6252.2502.31243.3223.375

sanity/output

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small2.52118.08969.5561.3601.21731.7621.644
large2.46518.07769.8621.3911.22932.2481.647
Retained tails and memory: sanity/output
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms2.82618.51583.2771.5171.27935.1502.276
small / Minimum ms2.41617.65167.2181.2291.12730.0591.561
small / Maximum ms2.99618.72291.5651.5701.29236.7712.372
small / RSS MiB6.25010.00022.6252.2502.37545.1993.500
large / p95 ms2.56818.31675.9123.2131.36933.7961.931
large / Minimum ms2.21317.61267.1141.2371.10529.5681.591
large / Maximum ms2.56818.35278.9354.4711.43034.1442.049
large / RSS MiB6.43810.00022.6252.2502.37545.1993.500

sanity/loops

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small3.34617.92367.9551.3871.28132.9844.709
large72.59225.14074.3121.9281.41935.264295.9
Retained tails and memory: sanity/loops
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms3.93318.59980.8671.5251.39133.9346.265
small / Minimum ms3.00617.65067.0611.2571.19631.3624.587
small / Maximum ms4.22718.67288.9411.5621.41134.1047.307
small / RSS MiB6.81210.00022.6252.3752.37545.6993.500
large / p95 ms75.56525.39179.2042.1111.44136.186354.1
large / Minimum ms71.83024.67072.3121.7351.29733.784290.0
large / Maximum ms76.70925.48880.3892.1141.44236.339393.7
large / RSS MiB6.75010.00022.6252.3752.37551.2643.500

sanity/function-calls

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small4.65018.03968.7621.4061.30132.1826.979
large193.729.07975.6753.7311.41935.443518.1
Retained tails and memory: sanity/function-calls
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms5.49419.28272.2241.5561.37535.3167.525
small / Minimum ms4.46117.40167.4271.2821.19330.3876.783
small / Maximum ms5.97320.09072.3181.6141.37735.5267.834
small / RSS MiB6.81210.00022.6252.3752.37545.4493.500
large / p95 ms199.329.55177.8634.9831.49840.979542.2
large / Minimum ms182.528.40773.2503.4301.27733.444512.9
large / Maximum ms200.529.59978.1595.9071.54642.986544.4
large / RSS MiB6.81210.00022.6252.3752.37551.3243.500

arrays-strings-hash/scan

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small3.55617.91168.0511.4371.29131.9635.215
large82.87424.01276.1722.1541.37438.856347.4
Retained tails and memory: arrays-strings-hash/scan
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms4.79518.43970.4921.5982.20132.9625.484
small / Minimum ms3.37417.46167.0831.2591.20530.1725.103
small / Maximum ms5.66418.54370.9251.6612.90533.1985.487
small / RSS MiB6.75010.00022.6252.3752.37545.6993.500
large / p95 ms85.97626.82980.4632.3611.51242.173368.3
large / Minimum ms80.75923.65474.6131.9951.27535.976342.9
large / Maximum ms86.80728.24181.3972.4811.56042.803379.0
large / RSS MiB6.75010.00022.6252.3752.37552.6993.500

arrays-strings-hash/frequency-count

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small7.06818.06269.5391.6381.31233.2868.547
large416.551.608100.523.3493.02239.929670.4
Retained tails and memory: arrays-strings-hash/frequency-count
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms7.61518.92871.2081.7631.40635.8089.361
small / Minimum ms6.86517.72168.0121.5071.22832.0258.344
small / Maximum ms7.68419.45471.4501.7971.42336.3679.426
small / RSS MiB6.81210.00022.6252.3752.37545.9513.562
large / p95 ms436.752.878106.924.5373.46741.154684.9
large / Minimum ms399.751.14597.26222.9112.85337.867660.5
large / Maximum ms438.353.054109.024.6903.63341.262688.0
large / RSS MiB6.75010.00022.7502.3752.37551.7033.500

arrays-strings-hash/sliding-window

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small5.28718.23167.9461.4581.33933.77713.274
large250.143.59079.2706.3792.40446.9215,056.6
Retained tails and memory: arrays-strings-hash/sliding-window
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms5.85218.74071.0241.6551.43435.97414.460
small / Minimum ms4.98017.84366.7491.3441.22531.12512.968
small / Maximum ms6.05318.89072.2461.7571.43636.52515.049
small / RSS MiB7.12510.00022.6252.3752.37545.9493.625
large / p95 ms257.945.92682.8517.4942.82049.4865,112.5
large / Minimum ms245.141.61078.5336.1202.34044.5425,019.3
large / Maximum ms259.346.66083.4037.5963.00949.8235,115.7
large / RSS MiB25.52713.75023.8014.2503.31252.45320.227

arrays-strings-hash/sort-index

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small6.84717.75668.6791.6281.50834.9927.391
large511.623.05278.73436.89134.92446.026211.8
Retained tails and memory: arrays-strings-hash/sort-index
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms7.11118.46170.4811.7641.79342.8607.516
small / Minimum ms6.50817.44566.8771.5241.41631.3677.248
small / Maximum ms7.21118.66370.5081.7741.86544.0967.581
small / RSS MiB7.96910.00022.7502.3752.37546.0743.750
large / p95 ms538.624.63281.10540.57939.89948.476219.8
large / Minimum ms492.922.38676.23336.08334.00243.450208.0
large / Maximum ms540.424.98081.34842.01740.76048.546220.4
large / RSS MiB139.013.75025.0514.3753.25053.20127.914

arrays-strings-hash/map-set

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small4.70118.06971.8601.4431.39534.4094.515
large212.728.64293.2737.2242.63345.464271.5
Retained tails and memory: arrays-strings-hash/map-set
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms4.88619.06176.2991.5661.77837.1834.923
small / Minimum ms4.65117.59669.2781.4031.27031.7064.396
small / Maximum ms4.89619.34977.2801.5951.77837.6535.083
small / RSS MiB7.00010.12522.8752.3752.37545.4493.625
large / p95 ms223.229.46295.6347.8263.15249.602291.7
large / Minimum ms203.027.64191.7276.8362.56143.265265.0
large / Maximum ms224.529.52596.2187.8873.47050.312301.9
large / RSS MiB30.10018.34027.7584.2503.37556.44714.625

dynamic-programming/fibonacci

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small2.81717.85368.5391.3511.26334.014—
large141.532.82782.6222.7882.06040.490—
Retained tails and memory: dynamic-programming/fibonacci
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms2.97220.76370.5531.4971.33039.660—
small / Minimum ms2.68817.43066.8001.3101.14831.341—
small / Maximum ms2.98722.57370.6291.5471.33342.011—
small / RSS MiB6.81210.00022.6252.3752.37545.953—
large / p95 ms144.233.82485.3423.0242.22047.839—
large / Minimum ms140.831.79279.8852.6741.97336.071—
large / Maximum ms144.334.04586.1823.1912.22152.281—
large / RSS MiB6.75010.00022.7502.3752.37553.574—

graphs-trees-search/bfs

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small11.40519.18469.2491.8681.98644.393—
large799.496.861121.735.28116.93282.224—
Retained tails and memory: graphs-trees-search/bfs
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms11.95220.45572.8011.9892.21446.937—
small / Minimum ms11.14018.43668.0541.8101.93433.727—
small / Maximum ms12.08420.53473.7782.0002.27747.743—
small / RSS MiB7.25010.12522.6252.5002.50053.738—
large / p95 ms871.8102.3127.635.99817.64095.539—
large / Minimum ms786.495.093117.934.79216.59075.938—
large / Maximum ms906.1103.2128.636.01017.794103.4—
large / RSS MiB32.77113.79326.0006.3755.62564.602—

structured-data/json-parse

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small4.26923.70275.255——33.976—
large182.179.343174.6——66.988—
Retained tails and memory: structured-data/json-parse
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms4.81926.78680.203——40.134—
small / Minimum ms4.17123.14271.841——31.176—
small / Maximum ms5.23327.35980.602——43.525—
small / RSS MiB7.55111.00023.000——45.516—
large / p95 ms198.698.836177.7——74.650—
large / Minimum ms177.977.995170.8——63.364—
large / Maximum ms208.6109.2178.5——75.589—
large / RSS MiB122.634.98850.125——57.027—

structured-data/json-transform

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small7.18624.47074.607——35.514—
large462.975.314138.1——74.546—
Retained tails and memory: structured-data/json-transform
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms8.86530.20476.414——36.710—
small / Minimum ms7.01523.59471.680——31.165—
small / Maximum ms9.96830.38976.686——36.810—
small / RSS MiB7.37510.87523.000——46.076—
large / p95 ms485.082.764144.2——84.187—
large / Minimum ms453.772.900133.5——70.570—
large / Maximum ms499.686.024146.7——86.731—
large / RSS MiB94.34633.00040.375——68.699—

structured-data/json-traverse

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small6.23523.98174.291——34.083—
large370.483.812182.8——68.608—
Retained tails and memory: structured-data/json-traverse
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms7.53829.32376.513——42.642—
small / Minimum ms6.04023.22872.255——31.187—
small / Maximum ms8.19732.58976.839——47.528—
small / RSS MiB7.61311.06223.000——46.137—
large / p95 ms391.4106.3186.8——76.285—
large / Minimum ms365.481.262178.0——66.434—
large / Maximum ms394.3120.1188.3——77.410—
large / RSS MiB122.634.99050.125——62.656—

filesystem/traverse

Fresh-process median ms; 10 measured samples
Sizeniftpythonrubylua54luajitnodebash
small3.10423.20169.0374.7484.61434.4035.250
large25.00530.24872.0587.6497.64148.9288.270
Retained tails and memory: filesystem/traverse
Separate descriptive metrics; RSS is waited-child high-water, not a combined ranking
Size / metricniftpythonrubylua54luajitnodebash
small / p95 ms3.34525.36171.2074.9174.87044.1395.352
small / Minimum ms3.02222.77667.2524.6214.54431.6815.216
small / Maximum ms3.36326.34171.7724.9544.95950.0295.356
small / RSS MiB6.37510.62522.6252.5002.50046.0783.500
large / p95 ms25.90137.29377.0737.8768.33263.1258.860
large / Minimum ms24.39229.66669.4977.5397.43846.7958.059
large / Maximum ms26.42541.87877.2997.9278.74964.4399.028
large / RSS MiB9.00011.00023.1252.5002.50054.9493.375
Memory comparisons across all participating runtimes; median waited-child high-water RSS, not aggregate tree memory
RuntimeNo-op RSS MiBLarge traversal RSS MiB
nift5.8759.000
python10.00011.000
ruby22.62523.125
lua542.2502.500
luajit2.3752.500
node41.57454.949
bash3.5003.375

Measurement & correctness

Every sample earns its place.

Ten measured samples plus two retained warmups per job; serial execution, rotated order, C-supervised fork/exec-to-exit latency and Linux waited-child high-water RSS. Every invocation must exit successfully and match its golden output. Alternate numeric formatting is accepted only when exact finite Decimal values agree; rounded output does not count.

Preparation is outside timing. Every sample creates a fresh runtime process with OS caches uncontrolled. We call this fresh-process-repeated, correcting the old suite’s misleading identical cold/warm labels. Historical runs are not merged.

Implementation choices

Observation before interpretation.

Native/JIT collection mechanisms can earn an advantage in sustained computation; invocation cost matters more for tiny automation. Nift’s integrated file/data functionality may be useful without winning every row. No benchmark here prices maintainability or feature convenience.

Bash is excluded from structured-data, Fibonacci and BFS where unnatural. Its recursive file test uses find/wc; other implementations use native APIs. BFS compares idiomatic queue/distance structures rather than identical internals. JSON parse/traverse include the same fixture read. Helpers remain inside timing.

Frequency-count v2 streams counters consistently; sort-index describes sorting and indexed reads. The misleading two-pointer endpoint test is omitted. Three redundant sanity microbenchmarks and duplicate shell startup are omitted. JSON-mutate duplicated record transformation without proving persistent array mutation. Partial JSON-query and unimplemented SQLite/mixed/breadth families are explicit coverage gaps. More end-to-end practical workflows would strengthen relevance.

Separate recovery diagnostic

Same-node checks for the surprising changes.

Separate same-node diagnostic: exact clean source builds c8d9c266 (previous release), 7f7e487 (original candidate) and c14d068 (final), using the same GCC 13.3 / native Make -O2 configuration, CPU 0, ten measured samples plus two warmups per case/version, six-permutation adjacent ordering and unchanged source/output oracles. All 72 observations passed independent audit; these are not pooled into official peer tables.

Separate three-version recovery diagnostic; medians, 10 measured samples per cell
CaseRelease msOriginal candidate msFinal candidate ms
sanity/function-calls/small4.7107.3754.678
sanity/function-calls/large193.6469.4198.6

Small/large calls improved 36.56% / 57.69% from the original candidate, with disjoint ranges and every paired final observation faster. Final versus release differed by −0.032 ms / +5.019 ms (−0.67% / +2.59%), with overlapping ranges. This supports substantial recovery to near-release latency, not exact equality or a statistically established residual regression.

Findings and qualifications · All raw samples and build identities · Independent audit.

Practitioner judgement / AI-DX

Choose for the actual workflow.

For a standalone general-purpose script, especially sustained data/compute work, I would usually choose Python (or a workload-appropriate native/JIT runtime), using the peer rows rather than Nift’s startup cost alone. Inside a Nift-owned project combining templates, files, build policy and tasks, I would choose Nift where the shared runtime and explicit contracts simplify agent maintenance. Human-plus-agent and agent-primary choices depend on those project requirements; the benchmark does not measure authoring error rates or prove that one language is universally best.

Machine-readable inputs, ownership and dependencies can be useful explicitness rather than redundant ceremony. These qualitative judgements do not turn the harness’s golden-output/fixture checks into automatic product guarantees. Memory remains a separately qualified waited-child high-water measure, not aggregate process-tree usage or a combined performance score.

Frozen environment

Exact source, tools and boundaries.

Final candidate Nift 4.12.0, exact clean source c14d06835bca515a5281e41da0e40219c2d60ef0; CLI SHA-256 7dd42dcee5ca4a6965f0823c0ae59198282da1eb77e0fcd4cae93a537870a6fb. Native Make -O2, GCC 13.3; dedicated g6-standard-4 (8 GB / four vCPUs), Ubuntu 24.04, timed processes pinned to CPU 0. OS caches are uncontrolled; this is not machine-cold timing. Historical hosts and diagnostic cohorts are never pooled.

Detected on this suite’s final measurement host
SystemMeasured version
niftNift v4.12.0
pythonPython 3.12.3
rubyruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux-gnu]
lua54Lua 5.4.6 Copyright (C) 1994-2023 Lua.org, PUC-Rio
luajitLuaJIT 2.1.1703358377 -- Copyright (C) 2005-2023 Mike Pall. https://luajit.org/
nodev24.21.0
bashGNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)

Exact build identity · Frozen suite and tool pins · Actual compiler/package inventory.

Independent complete-count/distribution audit · Normalized measurements · Complete raw data and retained warmups. No failed or superseded attempt is substituted for this accepted series.

Reproduce / scrutinise

All observations are retained.

Complete accepted series; the frozen suite revision and exact invocation are recorded in its readiness and official controller files. Summaries are independently recomputed from raw observations.

Conclusion

Workload-specific evidence.

These results support bounded implementation comparisons, not one scripting-language league table. Algorithms are diagnostics; file/data rows start a practical corpus which should expand before making broad claims.

Nift Benchmarks

Three perspectives on one runtime.