| Crates.io | scriptr |
| lib.rs | scriptr |
| version | 0.1.4 |
| created_at | 2025-08-04 17:33:44.277712+00 |
| updated_at | 2025-08-04 19:24:06.754973+00 |
| description | Fast, caching launcher for Cargo single‑file packages |
| homepage | https://github.com/tekacs/scriptr |
| repository | https://github.com/tekacs/scriptr |
| max_upload_size | |
| id | 1780982 |
| size | 32,962 |
Fast launcher for Rust single-file packages. Cuts startup time from 200ms to 5ms by caching builds intelligently.
Cargo's single-file package feature (-Zscript) makes writing scripts in Rust super enjoyable. The front-matter syntax, the path forward of native scripting support, I really want to use that for all my scripts!
But... every invocation pays a startup tax. Even when nothing changed, cargo walks the entire dependency graph, checks fingerprints, and verifies timestamps. For scripts, the 200ms (minimum) delay is extremely noticeable. Python starts in 20ms. Your shell starts in 5ms.
scriptr wraps cargo's build process with caching:
cargo +nightly -ZscriptThis two-level fingerprinting means touching a file doesn't trigger rebuilds and most invocations finish in 5ms.
Install from crates.io:
cargo install scriptr
Or build from source:
git clone https://github.com/tekacs/scriptr
cd scriptr
cargo install --path .
Write your script with scriptr in the shebang:
#!/usr/bin/env scriptr
---
[dependencies]
clap = { version = "4.5", features = ["derive"] }
---
use clap::Parser;
#[derive(Parser)]
struct Args {
name: String,
}
fn main() {
let args = Args::parse();
println!("Hello, {}!", args.name);
}
Then:
chmod +x hello.rs
./hello.rs World # First run: ~1.5s (builds dependencies)
./hello.rs World # Subsequent runs: ~5ms
Unlike cargo -Zscript which requires .rs extensions, scriptr works with any filename:
chmod +x hello # No .rs extension needed
./hello World # Works exactly the same
Note: If you plan to also use cargo -Zscript directly with your scripts, stick with .rs extensions.
-d, --debug - Build in debug mode (default is release mode)-v, --verbose - Show detailed operation logging-f, --force - Force rebuild, ignoring cache-c, --clean - Clean cache before building-C, --clean-only - Clean cache and exit without running-H, --hash-only - Use only hash for comparison (skip mtime check)By default, scriptr builds in release mode for optimal performance. Use -d if you need debug symbols:
#!/usr/bin/env -S scriptr --debug
The -H flag is useful in environments where mtime is unreliable (like some network filesystems or CI environments).
Measured on M2 MacBook Pro:
Simple "Hello World" script:
| Tool | First Run | Subsequent Runs |
|---|---|---|
cargo -Zscript |
157ms | 157ms |
scriptr |
157ms | 4.6ms |
With clap dependency:
| Tool | First Run | Subsequent Runs |
|---|---|---|
cargo -Zscript |
~2s | 157ms |
scriptr |
190ms* | 4.8ms |
*First run only includes cargo build time since dependencies are already cached
That's a 34x speedup for cached runs!
The 4-5ms overhead includes: process spawn, cache lookup, mtime check, and exec.
Note that we deliberately DO NOT cache the binaries ourselves. We let cargo build them into the same location it ordinarily would. That way, if you directly use cargo --manifest-path <file> or cargo -Zscript <file> to run or poke at them, it'll use the same build. We cache only the mtime + hash, in:
~/.cache/scriptr/~/Library/Caches/scriptr/%LOCALAPPDATA%\scriptr\Cache keys are based on the script's absolute path. Each script gets its own metadata file tracking mtime, BLAKE3 hash, and binary location.
Works seamlessly with standard cargo workflows:
# These share the same build artifacts:
./script.rs # via scriptr
cargo +nightly -Zscript run script.rs # via cargo
Both approaches use cargo's default target directory, ensuring consistent behavior and garbage collection.
-Zscript)The underlying issue is being tracked in rust-lang/cargo#12207 - cargo needs to check many small files on every run, making the 200ms overhead fundamental to the current architecture. Until cargo implements content-based caching or other optimizations, scriptr provides a practical workaround.
MIT OR Apache-2.0