<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[John Nunemaker]]></title><description><![CDATA[John Nunemaker]]></description><link>https://www.johnnunemaker.com/</link><image><url>https://www.johnnunemaker.com/favicon.png</url><title>John Nunemaker</title><link>https://www.johnnunemaker.com/</link></image><generator>Ghost 6.30</generator><lastBuildDate>Tue, 14 Apr 2026 09:30:11 GMT</lastBuildDate><atom:link href="https://www.johnnunemaker.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[IndieRails Podcast: The Conductor]]></title><description><![CDATA[<p>I hopped on <a href="https://www.indierails.com/75?ref=johnnunemaker.com" rel="noreferrer">IndieRails with Jess and Jeremy</a> (<a href="https://www.johnnunemaker.com/indie-rails/">again</a>). We covered a lot of ground in about 90 minutes. Quick business catch up and then dove into how AI has changed pretty much everything about how I work.</p><p>Some of the highlights:</p><p><strong>Business Updates</strong>. Flipper Cloud almost doubled revenue last</p>]]></description><link>https://www.johnnunemaker.com/indierails-podcast-the-conductor/</link><guid isPermaLink="false">69bc48779a56dc000112fcff</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Thu, 19 Mar 2026 19:11:23 GMT</pubDate><content:encoded><![CDATA[<p>I hopped on <a href="https://www.indierails.com/75?ref=johnnunemaker.com" rel="noreferrer">IndieRails with Jess and Jeremy</a> (<a href="https://www.johnnunemaker.com/indie-rails/">again</a>). We covered a lot of ground in about 90 minutes. Quick business catch up and then dove into how AI has changed pretty much everything about how I work.</p><p>Some of the highlights:</p><p><strong>Business Updates</strong>. Flipper Cloud almost doubled revenue last year, with most of the growth in the last few months. No AI headwinds on docs or conversion. Fireside is stabilizing &#x2014; we flattened churn and had our first three month stretch of even or growing customers since taking it over. Momentum, the coworking space I invested in, is filling up and becoming a real community in South Bend.</p><p><strong>Following the Inspiration</strong>. I&apos;m a mood person. I follow the energy. Having multiple products at different stages (five, six, and seven figures) means there&apos;s always something that matches whatever I&apos;m feeling that day. I&apos;ve spent 20 years intentionally building toward that flexibility.</p><p><strong>Support-Driven Development</strong>. With Fireside, I&apos;m close to the customer again. Someone asks for a responsive player, I build one from scratch in three days. Someone wants playlists, done. Someone wants custom colors saved, done in an hour. They&apos;re blown away because the product had been dormant. That feedback loop is addicting.</p><p><strong>The Company Brain</strong>. For Box Out, I&apos;m building an internal AI system using LibreChat with MCPs for our read replica database, Stripe, and a custom internal API. The goal is letting our small team query business data naturally &#x2014; hydrate conference attendee lists, look up support patterns, pull subscriber counts. Eventually I&apos;ll wire in Metabase too for the verified reports.</p><p><strong>Working Styles</strong>. Jeremy, Jess, and I got into how different developers use AI differently. Garrett goes heavy on docs and specs and skills. I go vanilla &#x2014; whisper flow, let it roll, see what happens. Both approaches work. A lion doesn&apos;t concern himself with tokens.</p><p><strong>The Arbitrage</strong>. There&apos;s a window right now where you can get significantly more done. Not just a little more &#x2014; I&apos;d say I&apos;m working 1.3-1.5x the hours but shipping 10x. That won&apos;t last forever, but right now the gap between people using these tools and people who aren&apos;t is massive. And we&apos;re still just the nerds. Most people haven&apos;t even tried a chatbot yet.</p><p><strong>What&apos;s Next</strong>. I think the AI era means more people shipping more code, which means more demand for developer tools &#x2014; monitoring, debugging, feature flags, experiment frameworks. That&apos;s why I&apos;m building an APM tool and planning to build something like GitHub Scientist next. The incumbents have no incentive for you to send less data. I think there&apos;s room for opinionated, affordable, AI-friendly developer tools.</p><p><strong>Conductor in the Web</strong>. What I really want is my dev environment on a server somewhere, always on, accessible from my phone. Spin up workspaces, prompt the next thing, check in from the couch or car line. Someone&apos;s going to solve this well in the next couple months. I&apos;d pay as much as I do for Claude for that solution.</p><p>We also got into the health and sustainability of all this, the farming lifestyle analogy (Jeremy and I both grew up in farm country), consulting economics in the AI era, and whether developers should be pushing harder toward ownership.</p><p><a href="https://www.indierails.com/75?ref=johnnunemaker.com">Listen here</a>.</p>]]></content:encoded></item><item><title><![CDATA[Rails Business Podcast (again)]]></title><description><![CDATA[How AI has changed my day-to-day as a developer. ]]></description><link>https://www.johnnunemaker.com/rails-business-podcast-again/</link><guid isPermaLink="false">69a9d7e93415240001a7309e</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Thu, 05 Mar 2026 20:14:06 GMT</pubDate><content:encoded><![CDATA[<p>I joined Brendan Buckingham and Ryan Frisch on the <a href="https://www.railsbusiness.com/2435951/episodes/18785602-john-nunemaker-on-ai-development?ref=johnnunemaker.com">Rails Business Podcast</a> to talk about how AI has changed my day-to-day as a developer. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.railsbusiness.com/2435951/episodes/18785602?ref=johnnunemaker.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">John Nunemaker on AI Development - Rails Business</div><div class="kg-bookmark-description">John Nunemaker returns to discuss how fast AI tooling has changed and argues tech leaders should adopt Claude Max (defaulting to Opus), set up agent-friendly local environments, and roll that out to their teams. He shares how his company built an&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/icon/Improved-20Podcast-20Image-1.png" alt><span class="kg-bookmark-author">Buzzsprout</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/thumbnail/Improved-20Podcast-20Image-3.png" alt onerror="this.style.display = &apos;none&apos;"></div></a></figure><p>Here are the highlights:</p><ul><li><strong>Your job as a tech leader is to go first.</strong> Get Claude Code with Opus, set up your local dev environment to be agent-friendly, then do the same for everyone on your team. I told everyone to get the $100 Max plan and offered to pay for it myself if they didn&apos;t think it was worth it. No one&apos;s taken me up on that.</li><li><strong>&quot;Brain,&quot; an AI-in-a-box for the company.</strong> I built an internal tool on a cheap Hetzner server using LibreChat, Postgres MCP (read-only replica), Stripe MCP, and a custom support MCP. Non-technical teammates can now ask natural language questions about customers, support trends, and revenue data without going through me. Secured it all behind Tailscale.</li><li><strong>The support insights were eye-opening.</strong> By slurping all our Crisp support conversations into a database and hooking it up as an MCP, I could ask things like &quot;summarize the last week of support requests&quot; and &quot;what&apos;s the tone of our support person?&quot; and get real answers. Next step is cron jobs that automatically post weekly summaries to Slack.</li><li><strong>Claude as a code review spin cycle.</strong> Team members now run Claude review locally, fix issues, then run <code>@claude</code> review on the GitHub PR before requesting human review. By the time it gets to me, it&apos;s usually ready to merge. This solved the bottleneck of everyone suddenly producing several PRs a day.</li><li><a href="https://www.conductor.build/?ref=johnnunemaker.com"><strong>Conductor</strong></a><strong> changed the game for parallel work.</strong> It manages isolated worktrees with separate databases, ports, and sessions. I can work on 3-5 things simultaneously, like a feature, a bug from Honeybadger, a support request, each in its own workspace. Setup and teardown scripts handle the isolation (fewer than 100 lines of code per app).</li><li><strong>People who couldn&apos;t write Rails before now can.</strong> <a href="https://zastrow.co/?ref=johnnunemaker.com">Phillip</a>, who we brought on for React/HTML, is now consistently making solid Rails PRs. Claude bridges the gap. The first PR needed some guidance on resiliency patterns, but after that, the spin cycle workflow handles it.</li><li><strong>Caddy for local HTTPS and custom domains.</strong> Drop it in your Procfile, point wildcard subdomains at it, and you get HTTPS locally with custom domain support. Solved a bunch of pain around cookies, CORS, and multi-workspace development.</li><li><strong>Stay bullish.</strong> Software engineering jobs are reportedly up about 4.5% month over month. There&apos;s an arbitrage window right now for teams that adopt these tools early. Don&apos;t get behind. That&apos;s the worst place to be.</li></ul>]]></content:encoded></item><item><title><![CDATA[Conducting Rails]]></title><description><![CDATA[<p>I&apos;ve been using <strong>@conductor_build</strong> heavily for weeks now and it&apos;s completely changed how I ship Ruby on Rails code when working with Claude models. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/2026/01/CleanShot-2026-01-29-at-18.18.27.png" class="kg-image" alt loading="lazy" width="2000" height="1202" srcset="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w600/2026/01/CleanShot-2026-01-29-at-18.18.27.png 600w, https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w1000/2026/01/CleanShot-2026-01-29-at-18.18.27.png 1000w, https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w1600/2026/01/CleanShot-2026-01-29-at-18.18.27.png 1600w, https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w2400/2026/01/CleanShot-2026-01-29-at-18.18.27.png 2400w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Conductor.build + Claude Opus 4.5</span></figcaption></figure><p>The multi-workspace, multi-process model feels unusual at first compared to a single editor flow, but</p>]]></description><link>https://www.johnnunemaker.com/conducting-rails/</link><guid isPermaLink="false">697be67539f7af00010afcf1</guid><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Fri, 30 Jan 2026 18:01:29 GMT</pubDate><content:encoded><![CDATA[<p>I&apos;ve been using <strong>@conductor_build</strong> heavily for weeks now and it&apos;s completely changed how I ship Ruby on Rails code when working with Claude models. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/2026/01/CleanShot-2026-01-29-at-18.18.27.png" class="kg-image" alt loading="lazy" width="2000" height="1202" srcset="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w600/2026/01/CleanShot-2026-01-29-at-18.18.27.png 600w, https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w1000/2026/01/CleanShot-2026-01-29-at-18.18.27.png 1000w, https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w1600/2026/01/CleanShot-2026-01-29-at-18.18.27.png 1600w, https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/size/w2400/2026/01/CleanShot-2026-01-29-at-18.18.27.png 2400w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Conductor.build + Claude Opus 4.5</span></figcaption></figure><p>The multi-workspace, multi-process model feels unusual at first compared to a single editor flow, but once you handle the Rails-specific quirks, your ability to work in parallel and ship faster skyrockets.</p><p>Here are the key practical steps and fixes I&apos;ve found essential for getting a Rails app running reliably across multiple Conductor workspaces. I&apos;ll try to keep this up to date as I find new things.</p><h2 id="copy-essential-gitignored-files">Copy essential gitignore&apos;d files</h2><p>Anything in <code>.gitignore</code> (credentials, <code>.env.local</code>, custom config files, active storage files in <code>tmp/</code> etc.) won&apos;t copy automatically. Manually <code>cp</code> these from your main <code>CONDUCTOR_ROOT</code> project directory into each workspace directory during initial setup. This keeps isolation clean without git<br>pollution.</p><h2 id="drive-everything-through-conductorport">Drive everything through <code>CONDUCTOR_PORT</code></h2><p>Conductor assigns dynamic ports&#x2014;make your app fully aware of them:</p><ul><li>Prefer <code>ENV[&apos;CONDUCTOR_PORT&apos;]</code> with a fallback (e.g., 3000).</li><li>Update Action Mailer <code>default_url_options</code>, controller/view host generation, and any internal URL building to use the current host + port.</li><li>Scope sessions and cookies by host + port to prevent collisions across workspaces. </li><li>A solid starting point for host and port handling is in <a href="https://gist.github.com/jnunemaker/7e4b909bce0bb8796d342bed06bd4c3e?ref=johnnunemaker.com">in this Gist</a>.</li></ul><h2 id="isolate-databases-for-parallel-execution">Isolate databases for parallel execution</h2><p>Shared test databases cause lock errors when running specs/tests concurrently across workspaces. Solution:</p><ul><ul><li>Create a per-workspace test database (suffix by workspace ID, <code>CONDUCTOR_PORT</code>, or Rails test env number).</li><li>Archive/drop the DB on workspace close.</li><li>For dev, if you create new dbs, seed them in the conductor setup.</li></ul></ul><h2 id="use-setup-run-and-teardown-scripts">Use setup, run, and teardown scripts</h2><p>Conductor supports these hooks natively. Automate workspace preparation (DB setup, seeding, file copying), server startup, and cleanup. This makes spinning up and tearing down consistent, repeatable, and fast.</p><p>Create <code>bin/conductor-setup</code> (or just mod <code>bin/setup</code> to work differently when conductor <code>ENV</code> vars are present) and <code>bin/conductor-teardown</code> (for when archive happens). <code>run</code> can just be <code>bin/dev</code> or whatever you use.</p><h2 id="cors-direct-uploads">CORS (direct uploads)</h2><p>One other issue is direct uploads to S3 and similar services. You&apos;ll want to be sure to use a dev bucket that allows any host/port. </p><pre><code class="language-bash">aws s3api put-bucket-cors --bucket your-bucket-dev --region us-east-1 --cors-configuration &apos;{
  &quot;CORSRules&quot;: [
    {
      &quot;AllowedHeaders&quot;: [&quot;*&quot;],
      &quot;AllowedMethods&quot;: [&quot;GET&quot;, &quot;POST&quot;, &quot;PUT&quot;, &quot;HEAD&quot;],
      &quot;AllowedOrigins&quot;: [&quot;*&quot;],
      &quot;MaxAgeSeconds&quot;: 3000
    }
  ]
}&apos;</code></pre><h2 id="rename-browser-tabs">Rename browser tabs</h2><p>Last but not least, rename your browser tabs. Trying to remember which port goes to which workspace is annoying. Just rename it once you open it to whatever the workspace is and you&apos;ll be golden. </p><h2 id="the-shift">The Shift</h2><p>The mindset shift to multiple concurrent processes and workspaces is the biggest hurdle. Once it clicks and your app behaves correctly across them, the productivity gain is massive. If you run into Rails-specific issues (subdomains, shared resources, etc.), the fixes are usually straightforward. Just ask claude/conductor how to fix them by updating the bin scripts I mentioned above.</p><ul><li>Conductor + Claude Opus has mostly replaced my editor for day-to-day work. I only fall back to a traditional editor for quick muscle-memory tasks.</li><li>The GitHub flow of Create PR &gt; Run CI &gt; Fix CI Failures &gt; Merge is SICK. </li><li>Every support request or thought that pops in my head becomes a workspace. </li><li>Heavy usage quickly justifies upgrading your Claude plan if you&apos;re on a lighter tier. The combination of claude + conductor unlocks a lotta throughput.</li></ul><p>If you&apos;re building with Rails and leaning on Claude heavily, Conductor is worth the initial setup effort. The payoff in shipping speed is real.</p><p>Always happy to brainstorm fixes for any Rails gotchas you hit&#x2014;just reach out.</p>]]></content:encoded></item><item><title><![CDATA[Rooted & Reaching Podcast Interview]]></title><description><![CDATA[<figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/nHBXcz-U9WA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Rooted &amp; Reaching: Building with Intention: Craft, Code, and Community with John Nunemaker"></iframe></figure><p>I recently sat down with Marty Mechtenberg on the Rooted and Reaching podcast to talk about my entrepreneurial journey, from struggling through my first programming class at Bethel to building multiple SaaS businesses while staying rooted in the South Bend area.</p><h2 id="the-early-days-learning-to-code-the-hard-way">The Early Days: Learning to Code (the Hard Way)</h2>]]></description><link>https://www.johnnunemaker.com/rooted-reaching-podcast-interview/</link><guid isPermaLink="false">6973cab932025b000175d69e</guid><category><![CDATA[business]]></category><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Fri, 23 Jan 2026 19:33:23 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/nHBXcz-U9WA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Rooted &amp; Reaching: Building with Intention: Craft, Code, and Community with John Nunemaker"></iframe></figure><p>I recently sat down with Marty Mechtenberg on the Rooted and Reaching podcast to talk about my entrepreneurial journey, from struggling through my first programming class at Bethel to building multiple SaaS businesses while staying rooted in the South Bend area.</p><h2 id="the-early-days-learning-to-code-the-hard-way">The Early Days: Learning to Code (the Hard Way)</h2><p>I wasn&apos;t a natural programmer. In my sophomore year at Bethel, I was pulling a D in my programming class while my future business partner Steve would walk in, hand in his homework, and leave. I spent hours in office hours, terrified of failure after a lifetime of straight A&apos;s. But that struggle taught me something important: once I learned something the hard way, it stuck.</p><p>What really hooked me was the internet. The moment I could make something and have my mom see it by typing a URL into her browser, that was magic. That&apos;s when programming stopped being abstract loops on a screen and became something I couldn&apos;t stop doing.</p><h2 id="ordered-list-and-the-power-of-sharing">Ordered List and the Power of Sharing</h2><p>After Notre Dame, I joined my friend Steve Smith at Ordered List, a small agency. We had a simple philosophy: talk about everything we built. We blogged about our process, spoke at conferences, and contributed to open source. We weren&apos;t trying to be clever about marketing, it was just what we knew how to do.</p><p>That openness led to opportunities we never expected. Speaking at a Ruby conference in New Orleans, I reconnected with a friend who had started GitHub. One conversation led to another, and eventually GitHub acquired our five-person team in 2011.</p><h2 id="the-github-years-and-why-i-left">The GitHub Years (and Why I Left)</h2><p>GitHub was an incredible ride&#x2014;from 45 employees to over a thousand in just four years. But as the company grew, so did the layers between me and any real decision-making power. By 2016-17, I was seven layers deep and itching to get back to building things my own way.</p><p>When Microsoft acquired GitHub in 2019, I took my exit. I needed to reclaim my indie spirit.</p><h2 id="building-for-flexibility-not-fortune">Building for Flexibility, Not Fortune</h2><p>Today I run multiple products: Box Out Sports (sports graphics for schools), Flipper (feature flags for developers), and Fireside (podcast hosting). The common thread? I&apos;ve always optimized for flexibility over maximum revenue.</p><p>I watched my dad work 90-hour weeks on the farm. I wanted the freedom to take a seven-week camping trip in the summer.</p><p>My advice for aspiring entrepreneurs: work your tail off in your 20s across different environments. Figure out what you actually like. Then optimize for the life you want, not just the biggest paycheck.</p><h2 id="why-south-bend">Why South Bend?</h2><p>People ask why I didn&apos;t move to San Francisco. The answer is simple: South Bend has everything I need. Good restaurants, Notre Dame athletics, a reasonable cost of living, no brutal traffic. It&apos;s big enough to have what matters, small enough to avoid what doesn&apos;t.</p><p>Plus, there&apos;s something special here I didn&apos;t expect to find: South Bend had its own watch company in the early 1900s, making precision pocket watches for the railroad industry. I&apos;ve become obsessed with finding and restoring these watches&#x2014;physical artifacts I can pass down to my kids, unlike software that rots in three years without constant care.</p><h2 id="the-ai-era">The AI Era</h2><p>I&apos;m not worried about AI taking over. I&apos;m obsessed with it. It&apos;s made me multilingual as a programmer. I can now contribute to Go projects despite being a Ruby developer for 20 years. The fundamentals I learned the hard way? They translate perfectly to telling Claude or ChatGPT exactly what I need.</p><p>The key is knowing what to ask for. Twenty years of programming principles don&apos;t disappear, they become the foundation for working with AI effectively.</p><p>Hope you enjoy!</p>]]></content:encoded></item><item><title><![CDATA[What makes you different]]></title><description><![CDATA[<p>Something that&apos;s been on my mind lately: <strong>Why is a customer going to choose my product</strong>? There&apos;s tens to hundreds or even thousands (looking at you CRM&apos;s) of every app for every problem. Why would someone choose mine? </p><p><strong>Price?</strong> I&apos;m a <a href="https://blog.flippercloud.io/per-seat-pricing-sucks/?ref=johnnunemaker.com" rel="noreferrer">firm</a></p>]]></description><link>https://www.johnnunemaker.com/what-makes-you-different/</link><guid isPermaLink="false">68ecff0eb3badd0001d7f3d6</guid><category><![CDATA[business]]></category><category><![CDATA[thoughts]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Mon, 13 Oct 2025 14:39:27 GMT</pubDate><content:encoded><![CDATA[<p>Something that&apos;s been on my mind lately: <strong>Why is a customer going to choose my product</strong>? There&apos;s tens to hundreds or even thousands (looking at you CRM&apos;s) of every app for every problem. Why would someone choose mine? </p><p><strong>Price?</strong> I&apos;m a <a href="https://blog.flippercloud.io/per-seat-pricing-sucks/?ref=johnnunemaker.com" rel="noreferrer">firm believer</a> in charging a price that works for the customer <strong>and</strong> for you. Competing on price is a race to the bottom. If this is where you are at, you&apos;ve already lost. </p><p><strong>Features?</strong> Maybe but that&apos;s a grind and a bit whack-a-mole. Having all the features someone could ever want waters down a product. Honestly, it makes products confusing. How do you build work flow and create value for the customer when the customer is anyone and the work flow is anything? </p><p><strong>Something else?</strong> I&apos;m becoming a bit obsessed with what makes you different. <em>People remember different</em>. And when someone gets out their card to buy something, you want them to remember you. </p><p>Our brains love to live on autopilot in a sea of sameness. This makes us hyper-sensitive to different. Even if that weren&apos;t true, different is great because it makes comparison difficult. Instead of granny smith verse golden delicious, it&apos;s apples and oranges.</p><h2 id="the-hot-dog">The Hot Dog</h2><p>In Unreasonable Hospitality, Will Guidara recounts the story of one particular table of diners at Eleven Madison. They were foodies in New York from overseas to enjoy the best restaurants. </p><p>They&apos;d probably had several amazing experiences. But one of them mentioned <strong>they were bummed they didn&apos;t get a new york hot dog</strong>. This was their last night in the city, so Will ran to the nearest hot dog cart, got a dog and convinced his chef to serve it to them.</p><p>Of all the places they dined, who do you think they remembered? Which story do you think they told people over and over? The hot dog. </p><p>Different is remembered. Different is shared. It&apos;s better than being better. And that&apos;s why I can&apos;t stop thinking about what makes my products different. </p><h2 id="an-example">An Example</h2><p>Let&apos;s talk about <a href="https://boxoutsports.com/?ref=johnnunemaker.com" rel="noreferrer">Box Out</a> for a moment as a practical example. </p><p>Our competition focuses on <em>infinite customization</em>. Move this logo wherever you want or make it bigger. Change the font or text size. Drag this. Drop that. All of them just re-create Photoshop in the browser with a bunch of stock templates to choose from. Heck, that is all canva is. </p><p>We do the opposite. We focus on <strong>speed</strong> (time to social timeline) and <strong>brand</strong> (<a href="https://boxoutsports.com/features/manage-users-with-set-it-and-forget-it-permissions?ref=johnnunemaker.com" rel="noreferrer">delegate</a> to students/interns but retain quality). How fast can we help you make a graphic to share with your followers (and then move on with your life).</p><p>Don&apos;t move things around, it&apos;s wasting time. <br>Lock down colors, fonts and templates. <br>Don&apos;t resize logos or text.</p><p>We&apos;re different. Those differences create constraints that actually guide us to build a better product. Sure, we&apos;ve been tempted to build drag and drop, but that would be a disservice to our customers. Their time is better spent on other things. </p><h3 id="trade-offs">Trade offs</h3><p>Everything is trade offs. Things like the list below would be dramatically harder or impossible if we allowed that. </p><ul><li><a href="https://boxoutsports.com/features/multi-format-graphics-create-once-get-three-formats-automatically?ref=johnnunemaker.com" rel="noreferrer"><strong>Multi-format</strong></a>. Different platforms prefer different sized graphics. We handle that for you. X gets widescreen, IG 4:5 (or now 3:4), Story format. <em>Fill out your data once and hit share</em>. Don&apos;t duplicate and resize and move stuff around.</li><li><a href="https://boxoutsports.com/features/generate-personalized-captions-with-ai-suggestions?ref=johnnunemaker.com" rel="noreferrer"><strong>Suggestions</strong></a>. Not sure what to say? Hit a button and get 5 options with different tones that <em>smell quite similar</em> to your previous shares. Of course they are based on the graphic you are attaching to the share.</li><li><strong>Built-ins</strong>. Need to <a href="https://boxoutsports.com/features/edit-your-images-in-a-flash?ref=johnnunemaker.com" rel="noreferrer">crop an image</a> or <a href="https://boxoutsports.com/features/effortlessly-edit-and-trim-videos?ref=johnnunemaker.com" rel="noreferrer">trim a video</a>? No problem. Do it right in the browser, right from the graphic you are creating. <em>No need to leave the browser</em>. We&apos;ll even <a href="https://boxoutsports.com/features/automatically-remove-the-background-from-images?ref=johnnunemaker.com" rel="noreferrer">remove the background</a> for a stunning PNG cut out on many graphics. Not ready to share yet? <a href="https://boxoutsports.com/features/planning-social-media-is-easy-with-scheduled-posts?ref=johnnunemaker.com" rel="noreferrer">Schedule</a> it for later.</li><li><strong>Autofill</strong>. We autofill fields for the graphic based on what you&apos;ve previously used, <a href="https://boxoutsports.com/features/sync-your-schedule-create-graphics-instantly?ref=johnnunemaker.com" rel="noreferrer">upcoming events</a>, your linked brand information, <a href="https://boxoutsports.com/features/grab-any-team-logo?ref=johnnunemaker.com" rel="noreferrer">opponents</a> linked brand information, live stats, etc. Autofill means <em>fewer fields to fill out</em>. </li><li><strong>Speed</strong>. We just spent months decreasing average graphic render time from 2.9 to 1.1 seconds. Rendering is so fast now that it feels live. </li></ul><p>For Box Out, it&apos;s easy to define and see the value those differences create for us (and our customers). Now it&apos;s time to think what those differences are and will be for <a href="https://fireside.fm/?ref=johnnunemaker.com" rel="noreferrer">Fireside</a> and <a href="https://www.flippercloud.io/?ref=johnnunemaker.com" rel="noreferrer">Flipper</a>... </p>]]></content:encoded></item><item><title><![CDATA[Self-Made is a Myth Podcast]]></title><description><![CDATA[Podcast interview where I share my journey building lasting SaaS businesses, the power of partnerships, and why I'm obsessed with onboarding, risk reduction, and hiring ‘batteries included’ people.]]></description><link>https://www.johnnunemaker.com/self-made-is-a-myth-podcast/</link><guid isPermaLink="false">68dd42338bb66e00017d4788</guid><category><![CDATA[podcast]]></category><category><![CDATA[business]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Wed, 01 Oct 2025 15:19:04 GMT</pubDate><content:encoded><![CDATA[<p>I&apos;m never one to turn down being on a podcast, especially since acquiring <a href="https://fireside.fm/?ref=johnnunemaker.com" rel="noreferrer">Fireside.fm</a>, a podcast host. So yesterday, I hopped on a call with Tim Campsall to chat about running <a href="https://boxoutsports.com/?ref=johnnunemaker.com" rel="noreferrer">Box Out</a> and <a href="https://verygoodsoftware.company/?ref=johnnunemaker.com" rel="noreferrer">Very Good</a>. And the crazy thing is it&apos;s already out on Youtube. I wasn&apos;t in my home office so my background was bleak and my audio was subpar but still a great conversation.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/14OZttvB-24?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="John Nunemaker - Box Out Sports: Self Made Is A Myth Interview"></iframe></figure><h2 id="highlights">Highlights</h2><ul><li>Shortest path between builders and users is critical.</li><li>Hire &#x201C;batteries included&#x201D; people who are self-driven.</li><li>I&#x2019;m not really good at anything specific. I&#x2019;m just good at being glue.</li><li>Measure progress (time tracking) and celebrate wins to avoid burnout.</li><li>Design products to save people time. Design your business to free your own time.</li><li>People buy from people. My dream as a developer is to build a good product and never talk to anyone, but it just doesn&#x2019;t work that way.</li></ul>]]></content:encoded></item><item><title><![CDATA[Giant Robots]]></title><description><![CDATA[<p>A few weeks back I <a href="https://podcast.thoughtbot.com/576?ref=johnnunemaker.com" rel="noreferrer">joined Chad on his Giant Robots podcast</a> to talk Ruby, Rails and a bit of business &#x2013; including our <a href="https://www.johnnunemaker.com/acquiring-fireside/" rel="noreferrer">acquisition of Fireside</a> last year. The episode just went live and I hope you enjoy it. </p><p><strong>Fun fact</strong>: their podcast is actually hosted on <a href="https://fireside.fm/?ref=johnnunemaker.com">Fireside</a> &#x2013;</p>]]></description><link>https://www.johnnunemaker.com/giant-robots/</link><guid isPermaLink="false">68386be4a899f60001586fb0</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Thu, 29 May 2025 14:19:23 GMT</pubDate><content:encoded><![CDATA[<p>A few weeks back I <a href="https://podcast.thoughtbot.com/576?ref=johnnunemaker.com" rel="noreferrer">joined Chad on his Giant Robots podcast</a> to talk Ruby, Rails and a bit of business &#x2013; including our <a href="https://www.johnnunemaker.com/acquiring-fireside/" rel="noreferrer">acquisition of Fireside</a> last year. The episode just went live and I hope you enjoy it. </p><p><strong>Fun fact</strong>: their podcast is actually hosted on <a href="https://fireside.fm/?ref=johnnunemaker.com">Fireside</a> &#x2013; inception! You can listen wherever you consume podcasts or on Fireside (below) or <a href="https://www.youtube.com/watch?v=URrk9eigXsI&amp;ref=johnnunemaker.com">youtube</a>. </p>
<!--kg-card-begin: html-->
<iframe src="https://player.fireside.fm/v2/DiNRb69N+NgFmOaBl?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>
<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Rails Business Podcast]]></title><description><![CDATA[<p>I had a nice chat with Brendan and Ryan on the <a href="https://www.railsbusiness.com/?ref=johnnunemaker.com" rel="noreferrer">Rails Business podcast</a> a few weeks ago and now its live! Search for &quot;Rails Business&quot; in your favorite podcast app or you can listen at the following link: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.railsbusiness.com/2435951/episodes/16978258-john-nunemaker?ref=johnnunemaker.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">John Nunemaker - Rails Business</div><div class="kg-bookmark-description">In this episode, Brendan</div></div></a></figure>]]></description><link>https://www.johnnunemaker.com/rails-business-podcast/</link><guid isPermaLink="false">67febf26dda93600012388df</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Tue, 15 Apr 2025 20:28:09 GMT</pubDate><content:encoded><![CDATA[<p>I had a nice chat with Brendan and Ryan on the <a href="https://www.railsbusiness.com/?ref=johnnunemaker.com" rel="noreferrer">Rails Business podcast</a> a few weeks ago and now its live! Search for &quot;Rails Business&quot; in your favorite podcast app or you can listen at the following link: </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.railsbusiness.com/2435951/episodes/16978258-john-nunemaker?ref=johnnunemaker.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">John Nunemaker - Rails Business</div><div class="kg-bookmark-description">In this episode, Brendan and Ryan welcome John Nunemaker.&amp;nbsp; John is a prominent figure in the Ruby community and, shares his journey into Ruby on Rails, his career evolution, and his unique approach to managing multiple projects simultaneously&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/icon/favicon-1.ico" alt><span class="kg-bookmark-author">Buzzsprout</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/thumbnail/Improved-20Podcast-20Image-1.png" alt onerror="this.style.display = &apos;none&apos;"></div></a></figure><p>If you want the tldr, we cover: </p><ul><li>my journey into Ruby and Rails</li><li>my current projects and Ruby usage</li><li>the role of AI in my dev process</li><li>how to balance multiple projects</li><li>time tracking and productivity</li><li>consistency across projects</li><li>the origin and success of Box Out</li><li>future plans</li></ul>]]></content:encoded></item><item><title><![CDATA[Ruby on Rails Podcast: Taking over Fireside.fm]]></title><description><![CDATA[<p>I was stoked when I discovered that the <a href="https://www.therubyonrailspodcast.com/?ref=johnnunemaker.com" rel="noreferrer">Ruby on Rails podcast</a> is hosted on our platform &#x2013; <a href="https://fireside.fm/?ref=johnnunemaker.com" rel="noreferrer">fireside.fm</a>. So I reached out to Elise for feedback and to volunteer Garrett and I for an episode.</p><p>We recorded last week and its <a href="https://www.therubyonrailspodcast.com/531?ref=johnnunemaker.com" rel="noreferrer">already live today</a>. Our chat covered taking</p>]]></description><link>https://www.johnnunemaker.com/ruby-on-rails-podcast-taking-over-fireside-fm/</link><guid isPermaLink="false">679157fe17cafd00013a38b2</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Wed, 22 Jan 2025 21:13:43 GMT</pubDate><content:encoded><![CDATA[<p>I was stoked when I discovered that the <a href="https://www.therubyonrailspodcast.com/?ref=johnnunemaker.com" rel="noreferrer">Ruby on Rails podcast</a> is hosted on our platform &#x2013; <a href="https://fireside.fm/?ref=johnnunemaker.com" rel="noreferrer">fireside.fm</a>. So I reached out to Elise for feedback and to volunteer Garrett and I for an episode.</p><p>We recorded last week and its <a href="https://www.therubyonrailspodcast.com/531?ref=johnnunemaker.com" rel="noreferrer">already live today</a>. Our chat covered taking over an outdated Rails app and all the progress we&apos;ve made modernizing it the past few months. We even threw in a few stories of battle scars earned. </p><p>Enjoy!</p>
<!--kg-card-begin: html-->
<iframe src="https://player.fireside.fm/v2/3OC19MC9+qjmEkYf2?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>
<!--kg-card-end: html-->
<p>P.S. It&apos;s been <a href="https://www.therubyonrailspodcast.com/289?ref=johnnunemaker.com" rel="noreferrer">5 years since I was last on</a> the rails pod (Brittany Martin was the host).</p>]]></content:encoded></item><item><title><![CDATA[Episode #4]]></title><description><![CDATA[<p>It&apos;s out and it&apos;s stout. Actually, I don&apos;t know if it&apos;s stout or not. I just like to rhyme (all the time).</p><h2 id="my-3-fav-quotes">My 3 Fav Quotes</h2><p>&#x201C;What if instead of discounts, we focused on lowering the risk for customers to try</p>]]></description><link>https://www.johnnunemaker.com/episode-4/</link><guid isPermaLink="false">67803f686aa8b3000115a029</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Thu, 09 Jan 2025 21:47:52 GMT</pubDate><content:encoded><![CDATA[<p>It&apos;s out and it&apos;s stout. Actually, I don&apos;t know if it&apos;s stout or not. I just like to rhyme (all the time).</p><h2 id="my-3-fav-quotes">My 3 Fav Quotes</h2><p>&#x201C;What if instead of discounts, we focused on lowering the risk for customers to try podcasting?&#x201D; &#x2013; Garrett</p><p>&#x201C;You don&apos;t have to go crazy and work a ton. You can you can achieve great success by turning a few levers. But sometimes it just takes a lot of work to figure out what those levers are.&#x201D; &#x2013; John</p><p>&quot;I&apos;m just thinking about swag, but that&apos;s a discussion from another day.&quot; &#x2013; Kris</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.fireside.fm/black-friday-reflections-and-new-year-opportunities/?ref=johnnunemaker.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Black Friday Reflections and New Year Opportunities</div><div class="kg-bookmark-description">I was hoping to get this out last year, but holidays got in the way of that (in a good way). So here is the last episode recorded in 2024, fresh for you to enjoy in 2025. * Black Friday Reflections and Trends * Rethinking Sales Strategies for Software * Technical Upgrades and</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/icon/logo-500x500.png" alt><span class="kg-bookmark-author">Fireside.fm Blog</span><span class="kg-bookmark-publisher">John Nunemaker</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/thumbnail/episode-4-2.jpg" alt onerror="this.style.display = &apos;none&apos;"></div></a></figure><p>Big shoutout to <a href="https://riverside.fm/?ref=johnnunemaker.com" rel="noreferrer">Riverside</a>. We use them to record and edit this. And I&apos;ve found it pretty fun the past couple times. </p>]]></content:encoded></item><item><title><![CDATA[Episode #3]]></title><description><![CDATA[<p>For those that haven&apos;t <a href="https://blog.fireside.fm/?ref=johnnunemaker.com#/portal/signup" rel="noreferrer">subscribed to the fireside blog</a> or the <a href="https://standinginthefire.fireside.fm/subscribe?ref=johnnunemaker.com" rel="noreferrer">podcast</a>, I figured I&apos;d update here as well. We released episode #3 on <a href="https://standinginthefire.fireside.fm/3?ref=johnnunemaker.com" rel="noreferrer">Mastering Prioritization in SaaS</a> last week. Give it a listen and subscribe in your favorite podcast app. At some point I&apos;</p>]]></description><link>https://www.johnnunemaker.com/episode-3/</link><guid isPermaLink="false">677442581f46d700010ceb6e</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Tue, 31 Dec 2024 19:33:13 GMT</pubDate><content:encoded><![CDATA[<p>For those that haven&apos;t <a href="https://blog.fireside.fm/?ref=johnnunemaker.com#/portal/signup" rel="noreferrer">subscribed to the fireside blog</a> or the <a href="https://standinginthefire.fireside.fm/subscribe?ref=johnnunemaker.com" rel="noreferrer">podcast</a>, I figured I&apos;d update here as well. We released episode #3 on <a href="https://standinginthefire.fireside.fm/3?ref=johnnunemaker.com" rel="noreferrer">Mastering Prioritization in SaaS</a> last week. Give it a listen and subscribe in your favorite podcast app. At some point I&apos;ll get too lazy to post here too. &#x1F604;</p><p>One of my favorite parts was the segment on time tracking, something that I&apos;ve found useful of late.</p>
<!--kg-card-begin: html-->
<iframe src="https://player.fireside.fm/v2/26YjJHTb+YBzaOy8I?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>
<!--kg-card-end: html-->
<p></p>]]></content:encoded></item><item><title><![CDATA[Episode #2]]></title><description><![CDATA[<p>Episode #1 went out last Thursday. Now here we are on Tuesday and <strong>ANOTHER EPISODE FOR YOU</strong>. I know right?! Christmas came early this year. </p><p>On today&apos;s episode, we hit on a few topics:</p><p>&#x1F64B; Customer feedback.<br>&#x1F616; Podcasting pains.<br>&#x1F195; Future features.<br>&#x1F3C6; Recent wins.</p><p>Just hit</p>]]></description><link>https://www.johnnunemaker.com/episode-2/</link><guid isPermaLink="false">67617de9cd9f180001dff388</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Tue, 17 Dec 2024 13:41:23 GMT</pubDate><content:encoded><![CDATA[<p>Episode #1 went out last Thursday. Now here we are on Tuesday and <strong>ANOTHER EPISODE FOR YOU</strong>. I know right?! Christmas came early this year. </p><p>On today&apos;s episode, we hit on a few topics:</p><p>&#x1F64B; Customer feedback.<br>&#x1F616; Podcasting pains.<br>&#x1F195; Future features.<br>&#x1F3C6; Recent wins.</p><p>Just hit play... you know you want to. And then be sure to <a href="https://standinginthefire.fireside.fm/subscribe?ref=johnnunemaker.com" rel="noreferrer">subscribe</a>. </p>
<!--kg-card-begin: html-->
<iframe src="https://player.fireside.fm/v2/26YjJHTb+k0zrWQdh?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>
<!--kg-card-end: html-->
<p>In the interest of getting better, we&apos;re improving something each episode. Today&apos;s improvement was a wee bit of intro/outro music. </p>]]></content:encoded></item><item><title><![CDATA[Episode #1]]></title><description><![CDATA[<p>We did it! The <a href="https://fireside.fm/?ref=johnnunemaker.com" rel="noreferrer">Fireside</a> crew went through the entire process of setting up a podcast and recording our first episodes. </p><p>#1 is live wherever you enjoy podcasts (probably). </p>
<!--kg-card-begin: html-->
<iframe src="https://player.fireside.fm/v2/26YjJHTb+3MIL6f6q?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>
<!--kg-card-end: html-->
<p>I never would have guessed how tedious it would be to get your first episode out the door. Now I have</p>]]></description><link>https://www.johnnunemaker.com/episode-1/</link><guid isPermaLink="false">675afab33eddcd00010149dc</guid><category><![CDATA[podcast]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Thu, 12 Dec 2024 15:05:32 GMT</pubDate><content:encoded><![CDATA[<p>We did it! The <a href="https://fireside.fm/?ref=johnnunemaker.com" rel="noreferrer">Fireside</a> crew went through the entire process of setting up a podcast and recording our first episodes. </p><p>#1 is live wherever you enjoy podcasts (probably). </p>
<!--kg-card-begin: html-->
<iframe src="https://player.fireside.fm/v2/26YjJHTb+3MIL6f6q?theme=dark" width="740" height="200" frameborder="0" scrolling="no"></iframe>
<!--kg-card-end: html-->
<p>I never would have guessed how tedious it would be to get your first episode out the door. Now I have a ton of respect for our customers, especially our non-technical ones, who have made it through this gauntlet. </p><p>So much information to fill out! I&apos;m looking forward to getting this process locked down so new episodes will be much easier. Also, planning to start paying for an editor. &#x1F923;</p><p>We set the quality bar very low for this. We know we&apos;ll get better with each episode  but we had to start somewhere. Enjoy!</p><p>And be sure to <a href="https://standinginthefire.fireside.fm/subscribe?ref=johnnunemaker.com" rel="noreferrer">subscribe</a>!</p>]]></content:encoded></item><item><title><![CDATA[Shrinking a Postgres Table]]></title><description><![CDATA[<p>Ok folks, this is kind of a weird one. I&apos;m going to put it in the &quot;you won&apos;t ever need this, but if you do, you are going to be glad I wrote this up for ya&quot; category. </p><p>As you may or may not</p>]]></description><link>https://www.johnnunemaker.com/shrinking-a-postgres-table/</link><guid isPermaLink="false">67486c0c940eed00015ded10</guid><category><![CDATA[TIL]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Thu, 28 Nov 2024 14:10:17 GMT</pubDate><content:encoded><![CDATA[<p>Ok folks, this is kind of a weird one. I&apos;m going to put it in the &quot;you won&apos;t ever need this, but if you do, you are going to be glad I wrote this up for ya&quot; category. </p><p>As you may or may not know, I recently <a href="https://www.johnnunemaker.com/acquiring-fireside/" rel="noreferrer">acquired fireside.fm</a>, an awesome podcast host. While investigating a slow query, I noticed that the database servers were at 87% disk space use. </p><pre><code class="language- bash">$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       158G  129G   21G  87% /</code></pre><p>I typically use a managed Postgres, which makes it real obvious when you are starting to use a lot of disk space and easy to fix. But this is self-managed Postgres on Linode. </p><p>Servers don&apos;t like to run out of disk space (or even get close to running out). </p><h2 id="what-is-taking-up-the-space">What is taking up the space?</h2><p>So I started up a casual chat with GitHub&apos;s Copilot. You know, the typical, &quot;how are you?&quot;, &quot;oh I&apos;m fine, you?&quot;, &quot;yeah, same&quot;, &quot;do you like long walks on the beach?&quot;, &quot;yeah, my database is about to fall over too&quot;. </p><p>I asked Copilot how I could quickly get the size of the database:</p><pre><code class="language-sql">SELECT pg_size_pretty(pg_database_size(current_database())) AS database_size;
-- 114 GB</code></pre><p>Unfortunately, my database was the problem, not some rogue log file or backup retention policy. </p><p>My next question was which table is taking up all the space:</p><pre><code class="language-sql">SELECT 
    table_name, 
    pg_size_pretty(pg_total_relation_size(table_name)) AS total_size
FROM 
    information_schema.tables
WHERE 
    table_schema = &apos;public&apos;
ORDER BY 
    pg_total_relation_size(table_name) DESC;</code></pre><p>The usual suspects filled up the top 10 (analytics/metrics):</p><pre><code class="language-bash">            table_name             | total_size 
-----------------------------------+------------
 downloads                         | 57 GB
 downloads_archive                 | 30 GB
 day_downloads                     | 12 GB
 location_downloads                | 6235 MB
 metrics                           | 3537 MB
 user_agent_downloads              | 2145 MB
 spotify_day_downloads             | 2072 MB
</code></pre><p><code>downloads</code> seemed the largest so I started there. I wasn&apos;t entirely sure how the table was used (again I&apos;m new to this app). So I poked around for min and max <code>created_at</code> times. To my surprise, there were rows going back to 2021.</p><h2 id="why-is-the-downloads-table-large">Why is the downloads table large? </h2><p>The <code>downloads</code> table seemed to be a record of all the raw downloads before they are aggregated into tables more efficient for querying in a web request. As downloads are processed, they are deleted from the table. </p><p>The problem was many records (10&apos;s of thousands an hour) were not being processed and thus not being deleted. Those downloads seemed to be for episodes that no longer exist for various reasons. </p><p>Over the course of many years, this added up to many 10&apos;s of millions of rows and 35% of the disk space. I sliced and diced several queries and determined that every download older than a few hours was effectively bad data and not processable. </p><p>Now I knew what my issue was, but I wasn&apos;t sure about the best fix. </p><h2 id="brainstorming-with-copilot">Brainstorming with Copilot</h2><p>If you don&apos;t know this already, Copilot is great for brainstorming stuff like this. Talk human to it and it&apos;ll throw ideas back to you. </p><p>Copilot really wanted me to delete the rows in batches of 1-10k and then <code>vacuum</code> at the end. But not <code>vacuum full</code> because that would lock the database and bring down the house. </p><p>I ran the first query to delete 1k records:</p><pre><code class="language-sql">WITH rows_to_delete AS (
    SELECT id
    FROM downloads
    WHERE created_at &lt; &apos;2022-01-01&apos;
    LIMIT 1000
)
DELETE FROM downloads
WHERE id IN (SELECT id FROM rows_to_delete);</code></pre><p>But it took like 20 seconds. </p><p>I wasn&apos;t going to sit around and run this 30 - 50 thousand more times. </p><p>I also didn&apos;t really feel like making a background job to handle this for me. </p><p>Additionally, copilot wasn&apos;t sure how much space would actually be freed up by a <code>vacuum</code> (as compared to a <code>vacuum full</code>).</p><p>The easiest, fastest and most guaranteed way to free up space for a table is to drop it. But I did want some data out of it. That&apos;s when I remembered table swapping. </p><p>I asked Copilot for the best way to clone the downloads table:</p><pre><code class="language-sql">CREATE TABLE downloads_new (LIKE downloads INCLUDING ALL);</code></pre><p>&#x1F192; </p><p>And how do I insert only the rows I need, those that are downloads for episodes that exist:</p><pre><code class="language-sql">INSERT INTO downloads_new 
  SELECT d.* FROM downloads d 
  INNER JOIN episodes e ON e.token = d.episode_token 
  WHERE date_trunc(&apos;day&apos;, d.created_at) &gt;= &apos;2024-11-27&apos;;</code></pre><p>&#x1F60E; </p><p>And lastly, how do I swap the tables:</p><pre><code class="language-sql">ALTER TABLE downloads RENAME TO downloads_old;
ALTER TABLE downloads_new RENAME TO downloads;</code></pre><p>Sure, I could have looked these up in the Postgres docs or on Stack Overflow, but the ability to paste in your schema for your table and say in English what you want to do and get exact commands to copy is just amazing. </p><p>The only bit left was to drop the original table with all the junk data:</p><pre><code class="language-sql">DROP TABLE downloads_old;</code></pre><p>At this point, I had a brand, spanking new <code>downloads</code> table with only 30-40k records (past hour or so of downloads) and a whole lot more disk space:</p><pre><code class="language-bash">$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       158G   80G   71G  53% /</code></pre><p>The best part is it took about 10 seconds to run the queries and I lost, at most, if anything, a few seconds of data during the data dump and table rename. </p><p><strong>A worthy trade off compared to hours of coding and babysitting.</strong></p><h2 id="brainstorming-with-real-people">Brainstorming with Real People</h2><p>Now, it&apos;s worth mentioning that I wasn&apos;t entirely sure if this was going to get me the result I hoped for (no downtime, low effort, and freed up space). </p><p>So first, I dropped into my handy dandy, top secret slack of battle scarred programmers who are smarter than me. </p><p>Akin to Copilot, I posed the same question and I got a variety of other options. I felt good about all of them, but none could compare (IMO) with the simplicity of the table swap.</p><p>No one seemed overly scared that the table swap wouldn&apos;t work. And I got a yes from two people who thought it would be easiest. That was enough to give me the confidence to try it first. </p><p>Cheers to top secret slacks with smart people and AI chat bots! &#x1F37B;</p><p>So that&apos;s how I spent my Thanksgiving morning! </p><p>And, honestly, I&apos;m good with that. Feeling thankful even.</p><p>I learned something new. I saved my database. </p><p>And now I&apos;m going to eat some great food and hang out with family sans a low undercurrent of stress wondering if my poor little database has crept from 87% to 88% disk usage or even higher!</p>]]></content:encoded></item><item><title><![CDATA[Founder Quest: Acquiring Fireside]]></title><description><![CDATA[<p>Last, but not least for this week, I was on <a href="https://www.founderquestpodcast.com/episodes/acquiring-fireside-with-john-nunemaker?ref=johnnunemaker.com" rel="noreferrer">Founder Quest</a>. I&apos;m doing my best third wheel impression over there and appreciate that Ben and Josh haven&apos;t kicked me off yet. We talked about a lot of things but mostly focused on the <a href="https://www.johnnunemaker.com/acquiring-fireside/" rel="noreferrer">fireside acquisition</a></p>]]></description><link>https://www.johnnunemaker.com/founder-quest-acquiring-fireside/</link><guid isPermaLink="false">67093e04a60d4300016686f0</guid><category><![CDATA[podcast]]></category><category><![CDATA[business]]></category><dc:creator><![CDATA[John Nunemaker]]></dc:creator><pubDate>Fri, 11 Oct 2024 15:26:40 GMT</pubDate><content:encoded><![CDATA[<p>Last, but not least for this week, I was on <a href="https://www.founderquestpodcast.com/episodes/acquiring-fireside-with-john-nunemaker?ref=johnnunemaker.com" rel="noreferrer">Founder Quest</a>. I&apos;m doing my best third wheel impression over there and appreciate that Ben and Josh haven&apos;t kicked me off yet. We talked about a lot of things but mostly focused on the <a href="https://www.johnnunemaker.com/acquiring-fireside/" rel="noreferrer">fireside acquisition</a>.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.founderquestpodcast.com/episodes/acquiring-fireside-with-john-nunemaker?ref=johnnunemaker.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">FounderQuest | Acquiring Fireside with John Nunemaker</div><div class="kg-bookmark-description">Josh and Ben talk with John about his recent acquisition of Fireside, covering the finances, pitfalls avoided, and more acquisition tips.https://www.johnnunemaker.com/acquiring-fireside/https://www&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/icon/LWZhdmljb24ucG5n.png" alt><span class="kg-bookmark-author">FounderQuest</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://storage.ghost.io/c/56/7c/567c72a3-ead5-46fd-9854-699a0bc53757/content/images/thumbnail/LmpwZw.webp" alt onerror="this.style.display = &apos;none&apos;"></div></a></figure><p>If you missed the other podcasts this week, here you go:</p><ul><li><a href="https://podcast.drbragg.dev/episodes/episode-41-john-nunemaker/?ref=johnnunemaker.com" rel="noreferrer">Code and the Coding Coders who Code it</a></li><li><a href="https://changelog.com/podcast/612?ref=johnnunemaker.com">Changelog: The moneyball approach</a></li></ul>]]></content:encoded></item></channel></rss>