BlogWhy Reinventing the Wheel Was the Right Call (what Ghost, Hashnode, and Substack couldn't give me)
Essay

Why Reinventing the Wheel Was the Right Call (what Ghost, Hashnode, and Substack couldn't give me)

March 31, 2026·6 min read
Part of 16Channels Blog

16Channels workspace

Ghost wants you to be a newsletter writer. WordPress wants you to be a publisher. Substack wants you to be an audience builder. Hashnode wants you to be a developer blogger. None of those models fit me.

I registered 16channels.com in June 2011. For almost fifteen years, the idea sat there. A hub, a sandbox, a single home for every project I wanted to build. The reason I never pulled it off wasn't lack of ideas. It was lack of process. I needed a development workflow fast enough to actually use in the time I had.

About six months ago that changed. I started experimenting with AI-assisted development rules for automating complex tasks. Things like wiring up a local API layer to pull and triage Sentry errors, or integrating Jira without leaving my editor. Once I saw how far that could go, the studio stopped being a someday project.

What none of them could give me was the architecture I needed. Not a blog with a portfolio section, but a real hub. One login across multiple subdomains. A place where any project I build can slot in and share the same identity layer. That's not a feature request. It's a different product category.

The real requirement: a hub, not a site

16channels.com is the front door and the identity layer. Every project I build gets its own subdomain. Idearc lives at idearc.16channels.com. The next one will too. One account, one login, access to everything.

No existing platform gives you that. They give you a site. Some give you a custom domain. None of them are designed to be an auth hub for a constellation of apps that have yet to be built.

That's the part that required building from scratch. Supabase Auth handles the identity layer. Next.js runs the main site. Sessions already carry across subdomains, and full SSO is close. Every request refreshes the session at the edge before it hits a route:

ts
// frontend/proxy.ts
export async function proxy(request: NextRequest) {
  let supabaseResponse = NextResponse.next({ request })

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() { return request.cookies.getAll() },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
          supabaseResponse = NextResponse.next({ request })
          cookiesToSet.forEach(({ name, value, options }) =>
            supabaseResponse.cookies.set(name, value, options)
          )
        },
      },
    }
  )

  // Refresh session — required for Server Components to read auth state
  const { data: { user } } = await supabase.auth.getUser()

  if (request.nextUrl.pathname.startsWith('/admin') && !user) {
    const loginUrl = request.nextUrl.clone()
    loginUrl.pathname = '/login'
    return NextResponse.redirect(loginUrl)
  }

  return supabaseResponse
}

Every subdomain app runs the same pattern against the same Supabase project. One session, recognized everywhere. Each new project slots into the same identity layer regardless of what it's built on. A Rails backend, a set of serverless functions, a new Next.js app. The framework doesn't care. The auth layer is already there. What changes is just the app behind the subdomain.

That flexibility is the point. The hub isn't designed around the projects I have today. It's designed to absorb whatever I build next without rearchitecting anything.

There's one more layer most people don't think about when they reach for an off-the-shelf platform. Every app on this hub runs on the same Supabase project, organized into separate schemas. Apps can talk to each other through the same data layer when it's useful. A project I'm tracking in one app can surface in another. Data that's relevant across contexts doesn't have to be duplicated or synced. It's just there.

16channels itself can eventually become a real control plane. Not just a landing page, but a single dashboard with visibility into every app on this platform.

Reinventing the wheel is sometimes the point

Building is sometimes the product. Every layer of 16channels is something I'd put on a resume:

  • Supabase Auth with cross-subdomain sessions
  • Next.js App Router with server components and edge-aware data fetching
  • A custom markdown editor with live syntax highlighting
  • Formatting toolbar with one-click bold, italic, headings, links, images, and code blocks
  • Keyboard shortcuts for the most common formatting operations
  • Live preview toggle that renders the post exactly as it will appear publicly, using the same rendering pipeline
  • Built-in Open Graph and social card management per post
  • Slug auto-generation, category and project linking, and a full media manager
  • AI-assisted content tools for excerpts, tags, and metadata
  • A theme system with flash-free switching
  • A full database migration workflow

These aren't incidental to the project. They are the project.

The blog exists because the building is happening. Take away the novel problems and the deliberate experiments, and there's nothing worth writing about. The platform and the content are the same project.

How I scoped it without over-engineering it

The goal was never feature parity with an existing platform. It was exactly the feature set I need, nothing I don't.

I used AI to analyze Ghost, Hashnode, Substack, and WordPress side by side, looking at their feature sets, their information architecture, and what actually mapped to my needs. Anything worth building got its own deep-dive conversation. Anything that didn't survive scrutiny got cut. The output was a clear priority stack: what to build now, what to defer, what to skip entirely.

The analysis started with a prompt like this:

less
You are a product analyst. I am building a custom blogging platform for a solo developer.
Compare the following platforms across these dimensions: post editor capabilities,
content organization, SEO/metadata, media management, reader engagement, and admin workflow.

Platforms: Ghost, Hashnode, Substack, WordPress

For each feature, note:
- Which platforms include it
- Whether it's table-stakes, differentiating, or advanced
- Whether a solo developer actually needs it

Output a feature matrix, then a prioritized build list for my use case.

What came back wasn't a generic list. It was a structured gap analysis specific to the use case, with clear reasoning for what to include, what to skip, and what to revisit later.

That whole process took hours, not days. The first version of 16channels shipped with exactly what I needed.

What I'd tell someone considering the same thing

If you're a developer who wants a platform that fits your exact workflow, or you're building something that needs to function as a hub across multiple apps, building your own is worth considering. If you just want to publish and distribution matters more than infrastructure, use Ghost. It's excellent. Platforms aren't bad. They're just built for someone specific.

If you do decide to build, the single biggest lesson from this project: do the feature analysis before you write a line of code. My first version had a text area, a tag field, a related project selector, and not much else. That wasn't a minimalist philosophy. It was just incomplete. I ended up retrofitting features that a proper gap analysis would have surfaced from the start.

The process isn't complicated. Compare your requirements against the platforms that exist. Look at what they include, what they skip, and why. Decide what you actually need. The goal isn't feature parity. It's a deliberate feature set. Skipping that analysis doesn't save time. It creates rework.

AI-assisted development makes this worse if you're not careful. The build is fast now. But if you carry the old habit of iterating your way to clarity, you just get faster rework cycles. The bottleneck isn't the build anymore. It's the planning. Do that up front, with the same rigor and the same tools, and then the build actually is fast.

Where this is heading

The foundation is already shared. Every app runs on the same Supabase project, organized into separate schemas. Sessions carry across subdomains. Apps can talk to each other through the same data layer when it's useful.

That makes a control plane possible. Not just a landing page, but a single dashboard with visibility into everything running under the hub. Activity, users, data from across every project, in one place.

The same architecture that runs a blog and a subdomain app can run a full CRM. A project manager. A client portal where someone can log in, see project updates, review deliverables, handle billing. The identity layer is already there. The data layer is already shared. Every new capability is just a new surface on top of infrastructure that already exists.

I have plans.

nextjssupabasecustom-platformauthenticationai-assisted-developmentweb-architecturedeveloper-workflow