<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>@dlhck — David Höck</title>
    <link>https://dlhck.com</link>
    <description>Builder, engineer and entrepreneur.</description>
    <language>en</language>
    <lastBuildDate>Sat, 14 Mar 2026 20:29:14 GMT</lastBuildDate>
    <atom:link href="https://dlhck.com/rss.xml" rel="self" type="application/rss+xml"/>
    <managingEditor>david@dlhck.com (David Höck)</managingEditor>
    <webMaster>david@dlhck.com (David Höck)</webMaster>
    <item>
      <title>Making Myself Irrelevant Was the Easy Part</title>
      <link>https://dlhck.com/thoughts/making-myself-irrelevant-was-the-easy-part</link>
      <guid isPermaLink="true">https://dlhck.com/thoughts/making-myself-irrelevant-was-the-easy-part</guid>
      <pubDate>Sat, 22 Nov 2025 00:00:00 GMT</pubDate>
      <description>After delegating everything and making myself irrelevant, I had to rediscover my purpose as CEO.</description>
      <content:encoded><![CDATA[<p>From January through October 2025, I found myself in a situation that would sound absurd to my 2019 self: <Highlight>I was struggling to find my place in my own company.</Highlight> Not because the business was failing—quite the opposite. <a href="https://elevantiq.com">Elevantiq</a> was profitable, growing, with an incredible team of more than 15 people across offices in Kitzbühel and Vienna, building <a href="https://vendure.io">Vendure</a>, one of the leading open-source headless commerce frameworks in the world. The problem was that I had successfully made myself irrelevant, and I had no idea what to do with that achievement.</p><p>This article is the start of documenting my personal journey from founder to what I hope will become a <em>true</em> CEO. I'm writing this because during my research, I found surprisingly few public resources about this specific struggle that technical founders face—the ones who can code, sell, and market, but suddenly don't know where they fit anymore. If you're reading this and nodding along, this is for you.</p><p><h3>The Comfort of Exhaustion</h3></p><p>When I started Elevantiq in 2019 from rural Kitzbühel, Austria—a place dominated by tourism and construction, not exactly a tech hub, known for the famous <a href="https://www.youtube.com/watch?v=jKPukQrwIiw">Hahnenkamm Ski Race</a> and loved by the millionaires and billionaires of this world—I had zero experience building a company. But I had the energy and hunger to do everything myself. In the morning I'd be building features for clients, then jump into meetings before lunch, carve out two hours for marketing, and immediately switch to emergency client support because something went wrong. Days didn't end at 5pm, they ended at 8 or 10pm, and I was exhausted. But it felt good. I could see my to-do list getting shorter, feel the progress in my bones through sheer physical exhaustion, and know that I was moving the company forward with my own two hands.</p><p>Everyone tells you the same thing as you grow: "Make yourself irrelevant. Step out of day-to-day operations. Focus on what's 2-3 years ahead, not the now." I read this in every business book, every founder biography, every leadership article. So I built a great leadership team—<a href="https://www.linkedin.com/in/max-page/">Max</a>, who gradually took over more and more operations starting in 2021 and eventually became COO, and <a href="https://www.linkedin.com/in/michael-bromley-ab1704156/">Michael</a>, who joined our universe in 2022 through a joint venture focused on Vendure and now leads all technical work as CTO. I trusted them completely, and they delivered beyond expectations. The team was committed in ways I never forced them to be, fixing bugs late Friday evenings not because they had to, but because they cared.</p><p>Here's what made the delegation "easy" in hindsight: <Highlight>I had hired people who were strong enough to not need me.</Highlight> When my anxiety kicked in later and I pushed to reconsider our entire strategy multiple times throughout the year, Max and Michael had strong enough convictions to push back. They didn't just execute my vision—they had their own, and they defended it. The company kept moving in the right direction not because I was steering it, but because I had built a system that could steer itself. This was exactly what I wanted, and exactly what terrified me.</p><p>But this created an unexpected problem: <Highlight>What was <em>my</em> role now?</Highlight></p><p><h3>The Identity Crisis of a Technical Founder</h3></p><p>I was left with marketing and sales. I don't dislike this work—it's necessary, and I'm decent at it—but it doesn't fulfill me the way engineering does. I did it because <Highlight>I'm used to doing things I don't love when they need to get done</Highlight>, and if it wasn't me, who would it be? But the moment an opportunity to code appeared—supporting Vendure's new admin dashboard, building the new website—I'd drop everything and dive in. Then I'd realize I was avoiding what I <em>should</em> be doing, force myself back to marketing tasks, but never deliver anything that felt meaningful to me because I was constantly monitoring what was happening on the engineering side.</p><p><Highlight>For the first time in my company's life, I couldn't see the day-to-day progress.</Highlight> I wasn't in the trenches anymore, and that meant I couldn't <em>feel</em> how well we were working, how fast we were moving forward. <Highlight>My mind filled that vacuum with anxiety.</Highlight> Were we heading in the wrong direction? Was our strategy wrong? Was the competition pulling ahead? Should we change everything? The urge to throw everything up in the air was overwhelming because I convinced myself it wasn't working—not because of any real evidence, but because I couldn't see the daily wins anymore.</p><p>And then there was the deeper issue: my self-worth. <Highlight>I had this idea that I needed to be the best software engineer in the company, that everyone should look up to me for my technical skills—my speed, my ability to solve problems the moment they arose.</Highlight> When I stepped back from that, my value to the company felt like it had dropped to zero. What was I actually doing that moved us forward if I wasn't coding? The question haunted me.</p><p><h3>Taking Space to Think</h3></p><p>By November 2025, I was spinning. I told Max and Michael I needed space until the end of the year and essentially stepped away, telling the team I was focusing on a private construction project with my brother. Everyone understood. The first two weeks I did basically nothing—spent time with my girlfriend, went to the gym, read books, occasionally coded for fun. But I also started researching. Not the company's problems. <em>My</em> problem.</p><p>My research broke into three phases:
1. Are there others who experience this?
2. What is a CEO actually supposed to do?
3. And most importantly, do I really want to be a CEO?</p><p>I searched for "technical founder identity crisis" and similar terms, diving through blogs, forums, and business publications. I found maybe five articles from other technical founders describing similar experiences—not many, but enough to know I wasn't alone. Then I immersed myself in understanding what CEOs actually do: reading books on leadership transitions, listening to podcasts with founder-CEOs, watching interviews with successful technical founders who made the leap, and buying articles from Harvard Business Review on the founder-to-CEO journey. This wasn't the surface-level "set vision and strategy" stuff—I wanted to understand what world-class CEOs actually spend their time on, how they think, how they create value when they're not personally building the product.</p><p>---</p><p>Here are some of my raw notes that I took while researching:</p><p>- As founder to need to shift <em>from operator to architect</em>
- <Highlight>The founder finds value in their own output; the CEO finds value in the system's output</Highlight>
- Founders manage employees; CEOs lead leaders
- The founder is a firefighter, addicted to the urgency of the next crisis. The CEO is a strategist, focused on the five-year horizon
- Founders believe the best product wins. CEOs know the best <em>culture</em> wins, because it can build any product
- Founders equate speed with doing things themselves, CEOs see scale in systems that run independently
- As a founder your self-worth becomes a function of your to-do list
- Becoming a CEO from a founder is ultimately about pulling away from daily operations. The discipline is in resisting the lure of the urgent.
- Instead of being the best worker in the room, the founder must design the system that makes work flow without them. This is the essence of the founder to CEO transition. It is not abandoning responsibility but elevating it.
- The 5 most important shifts from founder to CEO
    - doing→designing systems
    - deciding→coaching decisions
    - managing→leading leaders
    - short-term→long-term
    - product→culture obsession
- A founder brings an idea into the world. A CEO sets direction while building and motivating an entire organization to capitalize on the opportunity.
- Disseminate Culture from the Top by holding team discussions and view it as a strategy session 
- Getting mentors for different areas is incredibly important to always self-reflect and learn
- Creating space to reflect is massively important (aka taking vacation)
- Recruiting must be a top priority - the CEO sets the tone. The people you hire are your brand.
- Create alignment by establishing overarching corporate goals and empower each "unit" of the organization to create their own under this umbrella</p><p>---</p><p>The last question took longer. I tried to remember why I started this company in the first place. I went back through old notes and emails from 2019, when I was still freelancing. What I found was revealing: I had told everyone back then that I wanted to build a team because I was tired of working alone on someone else's projects. I wanted to work with others on <em>our</em> stuff—building a team, building a company, building products, delivering unique services.</p><p><Highlight>The hilarious realization: where I am now is exactly what I dreamed of back then.</Highlight></p><p>I had achieved my first major challenge—building a profitable, stable, growing company with an incredible team. But I had no next challenge focused on me as a person, on my own growth and development. The crisis wasn't that I had failed; it was that I had succeeded at the first mountain and couldn't see the next one to climb.</p><p><h3>Redefining Value</h3></p><p>Somewhere along the way, I had gotten the equation backwards. <Highlight>I thought making myself irrelevant meant making myself worthless.</Highlight> But the dream was never to be the best engineer in the room—it was to build something bigger than myself, to have a team executing a shared vision.</p><p>I decided my next challenge would be to become the best CEO I could be—measured not by traditional metrics, but by whether I'm genuinely learning new skills and staying out of my comfort zone of software engineering, even when coding feels easier. Success means resisting the pull back to what's familiar and mastering an entirely new set of skills, behaviors, and ways of thinking.</p><p>The shift required reframing everything: My value isn't measured by my personal output anymore, but by the company's output. Founders equate speed with doing things themselves; CEOs see scale in systems that run independently of them. I need to figure out how to make these systems visible to myself—what metrics, processes, and markers of progress matter when I'm not personally shipping code. I don't have all these answers yet, and that's part of the work ahead.</p><p><h3>Going Forward</h3></p><p>My focus is shifting entirely to what only a CEO can do: Culture. Systems. Recruiting. Strategy. Vision. Alignment. I'll still code occasionally, but with clear goals and oversight from others—otherwise I know I'll relapse and disappear into the flow state for weeks.</p><p>Hiring will become a major focus, not to suddenly scale to 40 people next year, but to invest seriously in employer branding, building a network of potential talent, and establishing ourselves in Vienna's and Europe's tech scene. I'm also hiring an experienced Growth leader to take over marketing entirely so I can focus on sales—something I actually love and get amazing feedback on, partly because my technical knowledge lets me connect dots quickly and give qualified answers instead of generic sales talk.</p><p>Most importantly, I'm being open with my team about this journey. Being vulnerable about the fact that nobody is born knowing how to be a CEO, that I'm learning too, and that this is completely normal.</p><p><h3>The Fire Returns</h3></p><p>My fire is back. My hunger is back. I'm more motivated going into 2026 than I've been in a while, knowing that this year will mark the next major step—for the organization, but also for me as a person.</p><p>But this isn't a success story yet—it's the beginning of one. I don't have the systems figured out. I don't know if I'll succeed at becoming a true CEO. I might discover I hate it, or that I'm terrible at it, or that the role doesn't suit me. What I do have is clarity on the challenge ahead and the fire to pursue it. That's enough to move forward with purpose.</p><p>I plan to write a follow-up article in July 2026 to share what I've learned, what worked, what didn't, and how this journey has evolved. Taking these two months to step back and think was the best decision I've made for myself and the company in years.</p><p>I keep coming back to one insight that reminds me daily why I'm doing this:</p><p>> A founder who continues to define their value by personal effort inevitably caps growth. A CEO, by contrast, defines value by the systems they design and the leaders they empower.</p><p>If you're a technical founder struggling with similar questions about your role, your value, and your purpose as your company grows—you're not alone. And the answer might be simpler than you think: <Highlight>the dream you're living now might be exactly the one you started with. You just need a new challenge to chase.</Highlight></p><p>---</p><p><em>This is the first in a series documenting my journey from founder to CEO. Follow along at <a href="https://dlhck.com">dlhck.com</a> for updates.</em></p>]]></content:encoded>
    </item>
    <item>
      <title>Founding the TypeORM Association</title>
      <link>https://dlhck.com/thoughts/founding-the-typeorm-association</link>
      <guid isPermaLink="true">https://dlhck.com/thoughts/founding-the-typeorm-association</guid>
      <pubDate>Fri, 21 Nov 2025 00:00:00 GMT</pubDate>
      <description>Our Path Forward at TypeORM</description>
      <content:encoded><![CDATA[<p>Last November, <a href="https://x.com/michlbrmly">Michael</a> and I took over maintenance of <a href="https://typeorm.io/">TypeORM</a>. Since then, we've assembled a dedicated group of maintainers, shipped 7 patch releases fixing hundreds of issues, and brought the project back to life. That was milestone one.</p><p>TypeORM stands now at more than 12M monthly downloads and 36k GitHub stars. The project is truly alive!</p><p>!<a href="/typeorm-downloads.svg">TypeORM Downloads</a></p><p>Now we're working toward v1.0.0 and our next big milestone: establishing an official TypeORM association with clear governance, committed maintainers, and sustainable funding.</p><p><h3>Why an Association in Austria?</h3></p><p>We're <Highlight>incorporating in Vienna, Austria</Highlight> for several practical reasons:</p><p>Vienna hosts numerous international non-profit organizations and institutions. Austria maintains political neutrality—important for a project open to everyone globally, regardless of geography or politics. Michael and I live here, making incorporation straightforward. The bureaucracy and costs are minimal.</p><p><h3>Our North Star</h3></p><p>We're building toward:</p><p>- <strong>Clear governance structure</strong> with a board steering technical direction and strategic partnerships
- <strong>Committed maintainers</strong> investing 2-4 hours weekly, compensated for their work so TypeORM isn't an afterthought
- <strong>Sustainable sponsorships</strong> that fund the maintenance team
- <strong>Market visibility</strong> alongside Drizzle, Prisma, and other modern ORMs
- <strong>Benefits and incentives</strong> that make sponsoring TypeORM attractive to companies and individuals</p><p><h3>The Roadmap</h3></p><p><strong>Step 1: Incorporation</strong>
Found the association with proper bylaws (~€50 incorporation cost). Elevantiq will cover upfront costs and submit invoices to OpenCollective.</p><p><strong>Step 2: Build the Board</strong>
Find a third board member responsible for technical steering—triaging, roadmap planning, releases, and community communication. Michael and I will focus on database company relationships, framework collaborations, and public communications.</p><p><strong>Step 3: Improve Financial Infrastructure</strong>
Move beyond OpenCollective's current limitations to better manage donations, funds, and payments to maintainers.</p><p><strong>Step 4: Grow the Maintenance Team</strong>
Build toward 6-8 maintainers over 18-24 months, each committing 2-4 hours weekly. Compensation will be buying-power adjusted hourly rates—not market rates, but fair reimbursement for opportunity cost.</p><p><strong>Step 5: Secure Sponsorships</strong>
Establish recurring donations from database companies, frameworks, and organizations to fund the team.</p><p><strong>Step 6: Establish Release Discipline</strong>
Create a maintainable release routine prioritizing stability over rapid innovation.</p><p><strong>Step 7: Transparency</strong>
Operate with open accounting—visible incoming sponsorships and outgoing payments.</p><p><h3>Join Us</h3></p><p><strong>Feedback</strong>: What are we missing? What could be better? <a href="mailto:maintainers@typeorm.io?subject=Association-Founding-Feedback">Let us know</a>.</p><p><strong>Third Board Seat</strong>: We're reaching out to candidates who've shown strong commitment over recent months.</p><p><strong>Maintenance Team</strong>: Interested in joining the official maintenance team? <a href="mailto:maintainers@typeorm.io?subject=Maintainer-Application">Email your application</a> and tell us why you should be part of TypeORM's future.</p><p><strong>Sponsorships</strong>: Work at a database company interested in collaboration? Have budget for open source sponsorships? <a href="mailto:maintainers@typeorm.io?subject=Sponsorship">Reach out to us</a>.</p><p>TypeORM has been a cornerstone of the TypeScript ecosystem. Together, we're building the foundation for its next chapter.</p>]]></content:encoded>
    </item>
    <item>
      <title>The Complete Guide to Self-Hosting Next.js at Scale</title>
      <link>https://dlhck.com/thoughts/the-complete-guide-to-self-hosting-nextjs-at-scale</link>
      <guid isPermaLink="true">https://dlhck.com/thoughts/the-complete-guide-to-self-hosting-nextjs-at-scale</guid>
      <pubDate>Sun, 24 Aug 2025 00:00:00 GMT</pubDate>
      <description>A comprehensive guide to self-hosting Next.js in production with horizontal scaling, covering critical solutions for distributed caching, image optimization, reverse proxy configuration, and deployment challenges learned from real-world experience.</description>
      <content:encoded><![CDATA[<p>After years of running Next.js applications serving thousands of users at <a href="https://elevantiq.com" target="_blank">Elevantiq</a>, I've learned that self-hosting Next.js in production
is fundamentally different from clicking "deploy" on Vercel. When you're dealing with horizontal scaling, multiple replicas, and enterprise-grade requirements,
the default Next.js setup breaks down in ways that aren't immediately obvious.</p><p>This guide contains <Highlight>every hard-won lesson</Highlight> from deploying and maintaining Next.js applications at scale. Whether you're using Kubernetes, Docker Swarm, or platforms like Northflank and Railway, these solutions will save you from the production challenges I've already faced.</p><p><h3>The Hidden Challenge: Why Next.js Breaks at Scale</h3></p><p>Here's what nobody tells you about self-hosting Next.js: <strong>the framework assumes it's running as a single instance</strong>. The moment you spin up multiple replicas for high availability (which you absolutely need in production), everything that touches the filesystem becomes a problem.</p><p>Next.js loves writing to disk. Cache files, optimized images, temporary data, it's all stored locally in <code>.next/cache</code>. This works perfectly on Vercel because they abstract this complexity away. But when you have three replicas running simultaneously, you get this challenging scenario:</p><p>- User hits replica 1: Cache miss, generates content, stores locally
- Same user hits replica 2: Cache miss again, regenerates identical content
- Result: Inconsistent performance, wasted resources, confused users</p><p>This guide covers six critical areas where Next.js needs special configuration for production self-hosting: Dockerfiles, reverse proxies, caching, image optimization, CDNs, and server actions. Get any of these wrong, and your application may not function as expected in production, often in ways that only appear under load.</p><p><h3>Important Context</h3></p><p>It's worth noting that Next.js documentation states that ISR and caching work "automatically when self-hosting" with <code>next start</code>. The challenges we're addressing here primarily emerge when:</p><p>- You need horizontal scaling with multiple replicas
- You're operating at significant scale (thousands of concurrent users)
- You require zero-downtime deployments
- You have strict performance SLAs</p><p>For smaller deployments or single-instance setups, many of these issues won't apply.</p><p><h3>A Note on Context and Scope</h3></p><p>This guide is based on real-world experience deploying Next.js applications serving thousands of concurrent users in enterprise e-commerce environments. The solutions presented here address challenges that primarily emerge at scale with:</p><p>- Multiple replica deployments
- Kubernetes or similar orchestration
- Strict performance and availability requirements
- Complex caching needs</p><p>Many of these issues are standard distributed systems challenges that aren't unique to Next.js. The framework handles many scenarios well out of the box, especially for single-instance deployments. These solutions are for when you need to go beyond the default setup.</p><p>Performance metrics mentioned are from production systems under NDA and will vary significantly based on your specific implementation, infrastructure, and traffic patterns.</p><p><h3>1. Production-Ready Dockerfiles: The Foundation</h3></p><p>Start with the <a href="https://github.com/vercel/next.js/blob/canary/examples/with-docker-multi-env/docker/production/Dockerfile">official Next.js multi-stage Dockerfile</a>, but don't use it as-is. Here are the essential modifications:</p><p><code>`</code>dockerfile
<h3>In your base stage</h3>
ENV NEXT_TELEMETRY_DISABLED=1</p><p><h3>Add health checks for zero-downtime deployments</h3>
EXPOSE 3000
HEALTHCHECK --interval=12s --timeout=12s --start-period=5s \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000 || exit 1
<code>`</code></p><p>:::info
Health checks are critical for zero-downtime deployments, but can be tricky to get right, as they might lead to restart loops. Please verify that health checks are working before deploying.</p><p>If you're using a platform like Northflank or Railway, they might have a health check feature that you can use. If not, you can use a simple HTTP health check like the one above.
:::</p><p><h3>Why Health Checks Matter More Than You Think</h3></p><p>Without proper health checks, your orchestrator doesn't know when a replica is ready to serve traffic. During deployments, this causes:</p><p>- Request failures as traffic routes to starting containers
- Downtime when rolling updates kill healthy replicas before new ones are ready
- Zombie containers that crashed but still receive traffic</p><p>The health check configuration above ensures:</p><p>- New replicas are fully started before receiving traffic
- Crashed replicas are detected and replaced within x seconds
- Zero-downtime deployments actually achieve zero downtime</p><p><h3>2. Reverse Proxy Configuration: The Streaming Killer</h3></p><p>Your reverse proxy or ingress controller (Traefik, NGINX, HAProxy, Kong) needs specific configuration for Next.js. The critical requirement: <strong>disable response buffering</strong>.</p><p>Without this, React Suspense and streaming responses may not function as expected. Your users see blank pages or experience massive delays as the proxy buffers the entire response before sending it.</p><p><h3>NGINX Configuration</h3></p><p>Add this header in your <code>next.config.js</code>:</p><p><code>`</code>javascript
module.exports = {
  async headers() {
    return [
      {
        source: "/:path*{/}?",
        headers: [
          {
            key: "X-Accel-Buffering",
            value: "no",
          },
        ],
      },
    ];
  },
};
<code>`</code></p><p><h3>Traefik with Docker Swarm</h3></p><p><code>`</code>yaml
labels:
  - "traefik.http.middlewares.nobuffering.buffering.maxResponseBodyBytes=0"
  - "traefik.http.routers.myservice.middlewares=nobuffering"
<code>`</code></p><p>This single configuration issue has caused more production incidents than any other in my experience. Test streaming responses explicitly before going live.</p><p><h3>3. Distributed Caching with Redis: The Filesystem Alternative</h3></p><p>The default filesystem cache is completely incompatible with horizontal scaling. You have three options:</p><p>1. <strong>Shared volume</strong> (doesn't work): File locking issues, race conditions, data corruption
2. <strong>Master-slave setup</strong> (challenging): Requires complex coordination to ensure only designated instances write to cache, which can limit write throughput
3. <strong>Redis</strong> (works perfectly): Centralized, fast, battle-tested</p><p><h3>Official Cache Handler Approach</h3></p><p>The Next.js documentation provides an example of creating a custom cache handler. Here's the official approach:</p><p><code>`</code>javascript
// From Next.js official documentation
module.exports = {
  cacheHandler: require.resolve("./cache-handler.js"),
  cacheMaxMemorySize: 0, // disable default in-memory caching
};
<code>`</code></p><p>While you can implement your own cache handler following the official documentation pattern, I strongly recommend <a href="https://github.com/trieb-work/nextjs-turbo-redis-cache">@trieb.work/nextjs-turbo-redis-cache</a> for its production-ready features. The official docs even provide a Redis example that you can adapt to your needs.</p><p>_Note: This is a third-party solution we've found reliable in production. It's not officially endorsed by Vercel/Next.js. Always evaluate third-party packages for your security and compliance requirements._</p><p>Basic setup:</p><p><code>`</code>javascript
const nextConfig = {
  cacheHandler: require.resolve("@trieb.work/nextjs-turbo-redis-cache"),
  cacheMaxMemorySize: 0, // Disable in-memory caching
};
<code>`</code></p><p><h3>Critical Warning: The Monorepo Trap</h3></p><p>If you're using a monorepo (Nx, Turborepo, etc.), <code>require.resolve</code> can cause connection failures. The cache handler file gets duplicated during build, breaking the singleton pattern. Solution:</p><p><code>`</code>javascript
const path = require("node:path");
const CopyPlugin = require("copy-webpack-plugin");</p><p>const nextConfig = {
  cacheHandler: path.join(__dirname, ".next/server/cache-handler.js"), // Absolute path
  cacheMaxMemorySize: 0,
  webpack: (config, { isServer }) => {
    if (isServer) {
      config.plugins.push(
        new CopyPlugin({
          patterns: [
            {
              from: "./cache-handler.js",
              to: "./cache-handler.js",
            },
          ],
        })
      );
    }
    return config;
  },
};
<code>`</code></p><p><h3>Performance Optimization: Cache Size Matters</h3></p><p>In our experience with large e-commerce deployments, we discovered that caching full API responses led to slower Redis read times. The solution:</p><p>- Pre-process data before caching
- Only cache essential fields
- Monitor cache item sizes (we target under 1MB based on our infrastructure)
- Monitor Redis memory usage constantly</p><p>Your optimal cache size will depend on your Redis configuration, network latency, and data structure.</p><p>Also, be extremely careful with data passed from server to client components. Large prop sets create:</p><p>- Massive cache entries
- Huge DOM sizes
- Slow hydration
- Poor Core Web Vitals</p><p><h3>4. Image Optimization: External Processing is Non-Negotiable</h3></p><p>Next.js's built-in Sharp-based image optimizer stores resized images on the filesystem. With multiple replicas, every instance processes the same images independently. This is wasteful and slow.</p><p><h3>Solution 1: Image Transformation Services</h3></p><p>Use <a href="https://imagekit.io">ImageKit</a>, <a href="https://techdocs.akamai.com/ivm/docs/imquery">Akamai</a>, or similar:</p><p>_Note: These are third-party services. Always evaluate them for your security, compliance, and cost requirements._</p><p><code>`</code>javascript
const customLoader = ({ src, width, quality }) => {
  return `https://cdn.your-company.com/transform?url=${src}&w=${width}&q=${
    quality || 75
  }`;
};</p><p>module.exports = {
  images: {
    loader: "custom",
    loaderFile: "./image-loader.js",
  },
};
<code>`</code></p><p><h3>Solution 2: Self-Hosted with IPX</h3></p><p>Deploy <a href="https://github.com/unjs/ipx">ipx</a> as a separate service:</p><p>_Note: IPX is a third-party open-source solution. Always evaluate third-party packages for your security and compliance requirements._</p><p>Benefits:</p><p>- Centralized image cache shared across all replicas
- Reduced memory usage in Next.js containers
- CDN-ready with proper cache headers
- Consistent performance across all instances</p><p><h3>5. CDN Configuration: Cache-Control is Everything</h3></p><p>A CDN dramatically improves performance, but misconfiguration breaks your application. The golden rule: <strong>Your CDN must respect the origin's Cache-Control headers</strong>.</p><p>Next.js sets different cache headers based on:</p><p>- <code>export const revalidate = 3600</code>
- Dynamic routes
- Authentication state
- Cookie presence</p><p>If your CDN ignores these headers, you'll serve stale content to logged-in users or cache personalized pages publicly.</p><p><h3>Testing Checklist</h3></p><p>Before production:</p><p>1. Verify static assets are cached (CSS, JS bundles)
2. Test that <code>revalidate</code> values are respected
3. Confirm dynamic routes bypass cache appropriately
4. Validate authenticated requests aren't cached
5. Check cache invalidation works as expected</p><p><h3>6. Server Actions: The Deployment Consistency Challenge</h3></p><p>Server Actions use encrypted identifiers that change with every build by default. During rolling deployments, this causes the dreaded error:</p><p>:::error
"Failed to find Server Action "XYZ". This request might be from an older or newer deployment."
:::</p><p><h3>The Fix</h3></p><p>Set a consistent encryption key per environment:</p><p><code>`</code>bash
<h3>In your .env file</h3>
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY=your-32-character-key-here
<code>`</code></p><p>Generate different keys for each environment (dev, staging, production) but keep them consistent across deployments within that environment.</p><p><h3>Security Consideration for Server Actions</h3></p><p>It's crucial to understand that according to the Next.js documentation, Server Actions "create a public HTTP endpoint and should be treated with the same security assumptions." This means:</p><p>- Always validate and authorize within your Server Actions
- Treat them like public API endpoints
- Never rely solely on encryption for security
- Implement proper authentication and authorization checks</p><p>The encryption key consistency we discussed above helps with deployment, but is not a security feature by itself.</p><p><h3>Real-World Performance Results</h3></p><p>After implementing these solutions in large-scale enterprise commerce projects:</p><p>- <strong>Response times</strong>: Significant reduction for cached content (specific metrics vary by implementation)
- <strong>Server load</strong>: Substantial decrease during peak traffic
- <strong>Deployment failures</strong>: Zero-downtime achieved consistently
- <strong>User experience</strong>: Eliminated inconsistent page load times</p><p>Note: These results are from enterprise deployments under NDA. Your results will vary based on traffic patterns, infrastructure, and implementation details.</p><p><h3>Your Production Checklist</h3></p><p>Before deploying self-hosted Next.js at scale:</p><p>- Multi-stage Dockerfile with health checks configured
- Reverse proxy with disabled buffering verified
- Redis cache handler installed and tested under load
- External image optimization service configured
- CDN respecting Cache-Control headers validated
- Server Actions encryption key set consistently
- Load testing completed with multiple replicas
- Monitoring for cache hit rates implemented
- Alerting for replica health configured
- Rollback strategy tested</p><p><h3>Conclusion</h3></p><p>Self-hosting Next.js at scale is absolutely achievable, but it requires understanding and solving these architectural challenges upfront. Every issue I've outlined here cost us hours or days of debugging in production. Learn from our mistakes.</p><p>The solutions in this guide are battle-tested with thousands of concurrent users. They work. But remember: production is where theory meets reality. Monitor everything, test thoroughly, and always have a rollback plan.</p><p>If you're implementing these solutions and hit edge cases I haven't covered, I'd love to hear about them. The Next.js ecosystem evolves rapidly, and sharing knowledge helps us all build better production systems.</p>]]></content:encoded>
    </item>
    <item>
      <title>First Article</title>
      <link>https://dlhck.com/thoughts/first-article</link>
      <guid isPermaLink="true">https://dlhck.com/thoughts/first-article</guid>
      <pubDate>Fri, 11 Jul 2025 00:00:00 GMT</pubDate>
      <description>Every journey starts with a first step.</description>
      <content:encoded><![CDATA[<p>I've had the idea of sharing my thoughts for a while now.</p><p>But I never found the time or the motivation to actually build my own website (again).</p><p>Building such a simple website is not tickling my brain enough to get me excited.</p><p>And I need excitement to get me going.</p><p>Thanks to Cursor and Next.js I was able to build this website in a few hours.</p><p>This article is just a memory for myself to remind me when I have started to write again.
Of course I already have some ideas for articles swirling around in my head, so let's hope that I'll stick with it.</p><p>Why do I want to write? Well, there are a few reasons and all of them are egotistical to some degree.</p><p>- I want to share my thoughts and ideas with the world.
- I want to improve my writing skills.
- I want to improve my thinking skills.
- I want to improve my communication skills.
- I want to improve my problem solving skills.
- I want to improve my decision making skills.
- I want to improve my leadership skills.</p><p>I'm not sure if I'll continue to write here, but I'm glad I took the first step.</p>]]></content:encoded>
    </item>
  </channel>
</rss>