<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mariano Álvarez</title>
    <description>The latest articles on DEV Community by Mariano Álvarez (@creativoma).</description>
    <link>https://dev.to/creativoma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F628332%2Feb375d66-49c4-405d-aef3-95c56fc5e043.jpeg</url>
      <title>DEV Community: Mariano Álvarez</title>
      <link>https://dev.to/creativoma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/creativoma"/>
    <language>en</language>
    <item>
      <title>Why I choose Bun for my projects, for now</title>
      <dc:creator>Mariano Álvarez</dc:creator>
      <pubDate>Tue, 11 Aug 2026 07:30:32 +0000</pubDate>
      <link>https://dev.to/creativoma/why-i-choose-bun-for-my-projects-for-now-47j9</link>
      <guid>https://dev.to/creativoma/why-i-choose-bun-for-my-projects-for-now-47j9</guid>
      <description>&lt;p&gt;For most of my career "JavaScript runtime" meant Node, full stop. That stopped being true a while ago. Deno and Bun are both stable, both used in production somewhere, and both worth an honest look instead of a reflex "Node just works." This is where I landed after actually running Bun on my own side projects for a while: I like it, I'm keeping it, and I'm not calling it permanent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually made me switch
&lt;/h2&gt;

&lt;p&gt;It wasn't a benchmark. It was &lt;code&gt;bun install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first time I ran it on a project with a few hundred dependencies, I assumed something had failed silently because it finished before I'd read the output. No &lt;code&gt;node_modules&lt;/code&gt; progress bar to stare at, no coffee break. That single, boring, repeated-dozens-of-times-a-day interaction is what made the difference for me, not a single flashy number.&lt;/p&gt;

&lt;p&gt;Everything else followed from there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun init
bun add hono zod
bun run dev      &lt;span class="c"&gt;# runs .ts directly, no ts-node, no build step&lt;/span&gt;
bun &lt;span class="nb"&gt;test&lt;/span&gt;         &lt;span class="c"&gt;# Jest-compatible API, no separate runner to install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One binary is the runtime, the package manager, the bundler, and the test runner. No &lt;code&gt;tsconfig&lt;/code&gt; gymnastics to run a script, no &lt;code&gt;jest.config&lt;/code&gt; to get a test suite going, no separate watcher. For a personal project I'm poking at in short bursts, every one of those is friction I used to just accept as the cost of doing JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm not claiming
&lt;/h2&gt;

&lt;p&gt;I'm deliberately not repeating throughput numbers here. Every runtime's team publishes benchmarks that make their own runtime look best, measured on a workload they picked. That's true of Bun's marketing as much as anyone else's, and I have no independent way to verify the specific figures floating around comparison posts. What I can vouch for, because I've felt it directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install and startup are consistently fast.&lt;/strong&gt; Not "4x" fast in some universal sense, but fast enough that I stopped thinking about it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript runs with zero setup.&lt;/strong&gt; &lt;code&gt;bun run script.ts&lt;/code&gt; just works — full syntax, no flags, no stripped-down subset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The built-in test runner and bundler are genuinely usable&lt;/strong&gt;, not toy versions you'll outgrow immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Node.js has closed a lot of this gap on its own. &lt;code&gt;node:test&lt;/code&gt; is stable, &lt;code&gt;--watch&lt;/code&gt; replaces &lt;code&gt;nodemon&lt;/code&gt; for most cases, and recent Node versions can execute TypeScript directly via type stripping — though only for "erasable" syntax; &lt;code&gt;enum&lt;/code&gt; and &lt;code&gt;namespace&lt;/code&gt; still need an experimental flag, and type stripping doesn't do actual type checking (keep &lt;code&gt;tsc --noEmit&lt;/code&gt; in CI regardless of runtime). Node's permission model is also real, and it's something Bun doesn't have an equivalent for: Bun runs with full trust, no sandboxing, so anything your dependencies can do, they can do unrestricted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I still don't reach for Bun
&lt;/h2&gt;

&lt;p&gt;Deno's pitch is worth taking seriously precisely because it's different from Bun's: deny-by-default permissions. A Deno script can't touch the filesystem, network, or environment variables unless you explicitly grant it. That's a structurally different security posture than either Node or Bun offer, and for anything handling secrets or third-party code I don't fully trust, it's the one I'd reach for instead.&lt;/p&gt;

&lt;p&gt;And for this portfolio specifically, I'm not touching anything — it stays on pnpm and Node, per the project's own conventions. Bun is where I run new personal tools, scripts, and small services I'm building from scratch, not where I migrate something that already works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual decision process
&lt;/h2&gt;

&lt;p&gt;The only test that matters is your own dependency tree and your own workload, not a chart. What I actually do before adopting Bun on something new:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the real &lt;code&gt;package.json&lt;/code&gt; and run the test suite.&lt;/strong&gt; If a dependency leans on a native addon Bun doesn't support cleanly, I find out in minutes, not mid-project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check where it needs to run.&lt;/strong&gt; Bun's hosting support keeps growing, but it isn't Node's "supported literally everywhere." I confirm the target platform before writing a line of code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept that this can change.&lt;/strong&gt; If I hit a wall — a package that won't cooperate, an observability tool that only instruments Node, a project that needs Deno's sandboxing more than Bun's speed — I'll use whichever runtime the project actually needs. Nothing here is a rule, it's a default.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Bun wins my day-to-day right now because the friction it removes is the friction I hit constantly: installs, TypeScript, running a test. That's not the same as saying it's objectively the best runtime, or that it will still be my default in a year. For now, on my own projects, it's the one that gets out of my way — and that's the whole bar it had to clear.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Docs: &lt;a href="https://bun.sh/docs" rel="noopener noreferrer"&gt;Bun&lt;/a&gt; · &lt;a href="https://nodejs.org/en/docs" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; · &lt;a href="https://docs.deno.com/" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>programming</category>
    </item>
    <item>
      <title>I tried stacked pull requests on my own portfolio</title>
      <dc:creator>Mariano Álvarez</dc:creator>
      <pubDate>Tue, 11 Aug 2026 07:29:06 +0000</pubDate>
      <link>https://dev.to/creativoma/i-tried-stacked-pull-requests-on-my-own-portfolio-52cp</link>
      <guid>https://dev.to/creativoma/i-tried-stacked-pull-requests-on-my-own-portfolio-52cp</guid>
      <description>&lt;p&gt;GitHub just announced &lt;a href="https://docs.github.com/en/pull-requests/how-tos/stacked-pull-requests" rel="noopener noreferrer"&gt;stacked pull requests&lt;/a&gt; in public preview. Instead of reading the changelog and moving on, I decided to actually try it on this same portfolio repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem it solves
&lt;/h2&gt;

&lt;p&gt;I've done the manual version of this before: branch off a big feature, realize it's too large to review in one shot, and split it into a chain of branches that each target the previous one. It works, but every rebase is manual, and if the bottom branch changes, you're rebasing the whole chain by hand.&lt;/p&gt;

&lt;p&gt;Stacked PRs formalize that pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ┌── feat/frontend     → PR #3 (base: feat/api-endpoints)  ← top
  ┌── feat/api-endpoints → PR #2 (base: feat/auth-layer)
 ┌── feat/auth-layer     → PR #1 (base: main)               ← bottom
main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each PR only shows the diff for its own layer. Merge the bottom PR and GitHub automatically retargets the one above it to &lt;code&gt;main&lt;/code&gt;. The key rule: if a layer depends on code from another layer, that dependency has to live in the same branch or a lower one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;p&gt;GitHub ships a CLI extension for the local workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh extension &lt;span class="nb"&gt;install &lt;/span&gt;github/gh-stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It needs &lt;code&gt;gh&lt;/code&gt; ≥ 2.90.0, and my local &lt;code&gt;gh&lt;/code&gt; was still on 2.83.2, so an upgrade came first. Once that was sorted, starting a stack looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack init blog-stacked-prs-scaffold
&lt;span class="c"&gt;# ... write code, then:&lt;/span&gt;
gh stack add &lt;span class="nt"&gt;-Am&lt;/span&gt; &lt;span class="s2"&gt;"feat: scaffold blog post about stacked pull requests"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;gh stack add&lt;/code&gt; either commits to the current branch (if it has no commits yet) or creates a new branch on top of the stack, depending on where you are. That's exactly the mechanic I used to write this post: this section you're reading is its own layer, sitting on top of the scaffold layer that added the post's metadata and title.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually stacked
&lt;/h2&gt;

&lt;p&gt;For this post I split the work into three layers instead of one big commit:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scaffold&lt;/strong&gt; — the entry in &lt;code&gt;data/blog-post.ts&lt;/code&gt; and the skeleton &lt;code&gt;page.mdx&lt;/code&gt; with just the title and intro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content&lt;/strong&gt; — this section, the actual body of the post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closing&lt;/strong&gt; — conclusion and cleanup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's a small example, but it maps to the real reason I'd reach for this on a bigger change: shared types or data first, the logic that depends on them next, and UI last. Each layer becomes a PR that's small enough to actually review carefully instead of skimming a 40-file diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd watch out for
&lt;/h2&gt;

&lt;p&gt;Stacked PRs aren't free. A few things worth keeping in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ordering discipline matters.&lt;/strong&gt; If you put a dependency in the wrong layer, you'll notice fast: the PR below won't build, or the one above will show changes that don't belong to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's a solo-repo-friendly workflow too.&lt;/strong&gt; I don't have reviewers on this portfolio, but splitting the work still forced me to think in terms of "what does this layer actually depend on," which is the same discipline that makes stacks worth it on a team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-fork stacks aren't supported.&lt;/strong&gt; Everything has to live in the same repository, so this doesn't help for external contributions to a project you don't have write access to.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The manual version of this — chained branches, hand rebasing — always worked, but it was tedious enough that I'd only bother for genuinely large changes. &lt;code&gt;gh stack&lt;/code&gt; removes enough of that friction that I'd consider using it for something as small as this post. The mechanism is simple: each layer is a branch, each branch is a PR, and the tool keeps the base branches in sync as the stack changes underneath.&lt;/p&gt;

&lt;p&gt;Next time I have a change that's too big for one clean review, I know exactly where to start.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Docs: &lt;a href="https://docs.github.com/en/pull-requests/how-tos/stacked-pull-requests" rel="noopener noreferrer"&gt;Stacked pull requests&lt;/a&gt; · Extension: &lt;a href="https://github.com/github/gh-stack" rel="noopener noreferrer"&gt;github/gh-stack&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>I ran Claude Code unattended, all night</title>
      <dc:creator>Mariano Álvarez</dc:creator>
      <pubDate>Tue, 11 Aug 2026 07:25:45 +0000</pubDate>
      <link>https://dev.to/creativoma/i-ran-claude-code-unattended-all-night-5c0j</link>
      <guid>https://dev.to/creativoma/i-ran-claude-code-unattended-all-night-5c0j</guid>
      <description>&lt;p&gt;I keep a running list of small, well-defined tasks I never get to: a missing health-check endpoint, a flaky test, a config file that could use a default. None of them are hard. All of them lose every day to whatever is actually on fire. So I built &lt;a href="https://github.com/creativoma/auto-claude" rel="noopener noreferrer"&gt;auto-claude&lt;/a&gt;, a bash loop that picks tasks off a queue, runs Claude Code against each one in isolation, and only keeps the result if a command I chose says it passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottleneck isn't the model
&lt;/h2&gt;

&lt;p&gt;The premise I started from: if the work is specified precisely enough, and something other than my judgment at 3 a.m. decides whether the result is acceptable, there's no reason a human needs to sit in the loop approving every step. That "something else" is a verification command — a test suite, a build, a lint pass, whatever proves the task worked. It either exits 0 or it doesn't. No vibes.&lt;/p&gt;

&lt;p&gt;That reframes the actual bottleneck. It's not model capability, it's task specification. A vague task produces a vague result regardless of how good the model is. A task with a closed objective, verifiable acceptance criteria, and pointers to the right files is bounded by the model's competence, not by how many hours I spend babysitting the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the loop works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queue/todo/*.md --&amp;gt; for each task:
                      git worktree from BASE_BRANCH   (my checkout stays untouched)
                      claude -p  &amp;lt;- prompts/build.md + the task
                      VERIFY_CMD
                        |- pass -&amp;gt; commit on branch auto/&amp;lt;task&amp;gt; [push] [PR]
                        |- fail -&amp;gt; claude -p --resume &amp;lt;- prompts/fix.md
                                   (bounded by MAX_FIXES)
                    --&amp;gt; queue/done/ or queue/failed/
                    --&amp;gt; logs/report-&amp;lt;timestamp&amp;gt;.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One task at a time, each in its own &lt;code&gt;git worktree&lt;/code&gt; so a bad run can't touch my actual checkout. If verification fails, Claude gets one more shot with a fix prompt, bounded by &lt;code&gt;MAX_FIXES&lt;/code&gt; so a stubborn task doesn't burn the whole night. In the morning I read one report file: pass or fail per task, branch, diffstat, duration, cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  The guardrails are the point
&lt;/h2&gt;

&lt;p&gt;The loop itself is maybe 300 lines of bash. Nothing clever. Where the actual engineering went is the list of things that go wrong when nobody's watching, and what stops each one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A run dying on a usage limit doesn't lose the task — it sleeps and resumes.&lt;/li&gt;
&lt;li&gt;A hung verification command doesn't freeze the night — it gets killed after a timeout.&lt;/li&gt;
&lt;li&gt;Two runs starting at once (a cron overrun plus me starting one manually) — a lock file refuses the second and recovers automatically if the first died mid-run.&lt;/li&gt;
&lt;li&gt;Nothing gets marked done without &lt;code&gt;VERIFY_CMD&lt;/code&gt; actually passing, and the prompts explicitly forbid deleting or skipping tests to get there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MAX_BUDGET_USD&lt;/code&gt; caps spend per invocation; the report totals the real cost.&lt;/li&gt;
&lt;li&gt;Everything defaults to &lt;strong&gt;not&lt;/strong&gt; pushing and &lt;strong&gt;not&lt;/strong&gt; opening a PR. The loop stops at a local branch until I've read enough mornings of reports to trust it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this makes the model more capable. It makes an incapable or confused run fail loudly and cheaply instead of quietly doing something wrong on a shared branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm not pretending
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;PERMISSION_FLAGS&lt;/code&gt; defaults to &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;, because that's what unattended operation actually requires — Claude runs shell commands, edits files, and reaches the network without asking. The worktree isolates my source tree, not my machine or my credentials. Anything inside that worktree can see whatever SSH keys, cloud sessions, and tokens my shell can see. I'm not describing that as a sandbox, because it isn't one. If I were pointing this at something I actually cared about protecting, I'd run it inside a container with only the credentials that specific task needs, and I'd replace the permission flag with an explicit allowlist instead of skipping the check entirely.&lt;/p&gt;

&lt;p&gt;Right now I run it against throwaway repos and side projects, &lt;code&gt;PUSH_BRANCH&lt;/code&gt; and &lt;code&gt;OPEN_PR&lt;/code&gt; both off, and I read every branch before it goes anywhere. That's not a limitation of the tool so much as the appropriate amount of trust for a script that executes AI-generated shell commands while I'm asleep.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changed
&lt;/h2&gt;

&lt;p&gt;Writing the task file is now the part that takes effort, which is the correct place for effort to go. "Add &lt;code&gt;GET /health&lt;/code&gt; returning &lt;code&gt;{"status":"ok"}&lt;/code&gt;" survives an unattended run. "Improve observability" does not — there's no verification command that can judge that, so it either loops forever trying to guess what I meant or passes something I didn't ask for. Once I started writing tasks like the first kind, the backlog of small annoying things actually started shrinking overnight instead of accumulating.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Repo: &lt;a href="https://github.com/creativoma/auto-claude" rel="noopener noreferrer"&gt;auto-claude&lt;/a&gt; on GitHub&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>claude</category>
      <category>coding</category>
    </item>
  </channel>
</rss>
