32 karma · joined June 21, 2020
It doesn't happen only when I build my apps, but also every time I find a good open-source project that ships as a single binary. Hosting it means one of the above again, or wrapping it in a container image when it was already deployable as a single file. Self-hostable single-binary projects are great until you have to host them.
So I built nibrun. You upload a binary executable, and you get an isolated Firecracker microVM (1 vCPU, 256 MiB) and an 8 GiB persisted volume. The volume is all yours to use, as if it was your local machine: write your SQLite file, JSONs, assets uploads. And it's instantly available via HTTPS. No extra config file or Docker image needed. It sleeps after 5 minutes idle and wakes up on incoming requests in ~120 ms.
For example, you can deploy PocketBase (single-binary Supabase clone) in one click: https://nibrun.com/deploy/pocketbase
And when you want to leave, the export button gives you back the binary and everything in the volume, so leaving only costs you the download of a zip file.
All open source, so you can even run the whole platform on your own AWS account: https://github.com/ilbertt/nibrun
Starred!
A friend of mine created something similar with just a few prompts, allo working locally, and he's stopped using Wispr Flow
- in JS/TS you don't have compile-time scripts that you can run like with Rust's macros, so you need to run a codegen command before running the type checks (disadvantage)
- I had to create a TS parser that goes and finds the tagged template functions with the sql statements, while sqlx has them "for free" because sql statements are the input to the macro itself (disadvantage)
- I use an in-memory Postgres (PGLite) to describe the queries, instead of requiring a running pg instance (advantage)
- I don't cache the statements and codegen for now like sqlx does, something that can be added later
I think they are similar in that they both substitute the dynamic params with no-ops like $1, $2, etc. before handing the sql statement to the pg's DESCRIBE function
You'll still probably have to manually override some column types using PG comments like: https://github.com/ilbertt/bun-sqlgen/blob/dee757ebc9c38aec7...
PGLite extensions: https://pglite.dev/extensions/#postgis
bun-sqlgen goes the other way. You keep writing raw SQL queries, just give each one a name.
A codegen step reads your migration `.sql` files, stands up a throwaway Postgres via PGlite (so no Docker) or SQLite, prepares every tagged query against it, and writes a `.d.ts` that maps each query name to its real result type. After that, plain `tsc` does the rest: `user.notExistingField` won't compile, and `display_name.length` gets flagged because the column is nullable.
Nullability was the annoying part. Postgres's describe doesn't hand you per-column nullability, so I infer it from the query plan plus the catalog, with manual overrides for the cases that genuinely can't be inferred. SQLite works too.
The runtime stays 100% Bun.sql, the generated file is the only artifact (commit it), and codegen is fast enough to rerun on save.
It's early (v0.1, built it for my own projects) so I'd mostly like to hear where it falls over.
Although I think a type-safe language is a better fit for CLIs, to let coding agents iterate faster and have less runtime bugs (help messages not updated, unknown flags, etc.)
It's extensible by design, and you can test single commands atomically.
I think there's a good opportunity for it to become the Next.js/Vercel of CLIs.
Really nice and simple stack: Bun + SQLite.
Good for personal use (one bot, one number) or for companies that want to give each of their users their own AI assistant reachable over WhatsApp.