Blog
SceneSKU Team 7 min read

Why I Built SceneSKU with Elixir and Ash Framework

A solo founder's honest take on why Elixir, Phoenix LiveView, and Ash Framework beat the fragmented JavaScript ecosystem for building a production SaaS — and what 'vibe coding' actually looks like in practice.

Reddit r/elixir — What do you think of the Elixir ecosystem honestly?

A question keeps surfacing on r/elixir: “Is the Elixir ecosystem actually enough for a modern SaaS? What’s the community psychology — is it ‘npm install everything’ like JavaScript, or ‘std lib is enough’ like Go?”

I can answer that directly. I’m a solo founder. I built SceneSKU — a platform that delivers AI-generated e-commerce scene packs and MedusaJS-compatible product data to headless commerce developers — entirely on Elixir, Phoenix LiveView, and the Ash Framework. No Next.js. No Python microservices. No infrastructure bloat. One developer. One server. A product that handles image generation pipelines, concurrent CSV exports, state machines, webhooks, billing, and a public REST API without complaint.

Here’s what I learned.


The Solo Developer Tax vs. Cohesive Systems

There’s a hidden cost to the JavaScript ecosystem that nobody talks about honestly. It’s not that the tools are bad — it’s the fragmentation tax you pay as a solo developer. You npm install your way into a stack where Next.js handles the frontend, an ORM handles the database, a validation library handles inputs, a queue library handles background jobs, and a completely separate type system (often handwritten TypeScript interfaces) glues it all together. The same concept — say, a “Scene Pack” — gets defined three separate times: once in the database schema, once in the API validation layer, and once as a TypeScript type on the frontend. Change one, and you’re hunting down the other two manually.

Go leans the other way. The standard library is excellent, but for anything beyond basics, you’re rolling your own or stitching together minimal primitives. That’s a different kind of tax — the “build everything yourself” tax.

Elixir sits in a genuinely different place. The community psychology is about cohesive systems, not package count. The BEAM virtual machine — the runtime Elixir runs on — handles concurrency, fault tolerance, and process isolation as first-class primitives, not add-ons. You don’t install a process manager. You don’t configure a separate worker pool. The language itself is the infrastructure.

On SceneSKU, I have a router that cleanly separates public pages, authenticated customer routes, a system admin section, REST API routes with per-key authentication and rate limiting, and a webhook pipeline — all in one file that reads like an intentional map of the entire application. No configuration sprawl. No separate service for each concern.


Phoenix LiveView: The API Layer That Doesn’t Exist

The single most impactful choice I made was using Phoenix LiveView for the entire customer dashboard. There is no REST API serving the frontend. There is no client-side state management library. There are no API route definitions duplicated between a backend server and a frontend client.

LiveView works by keeping page state on the server and sending minimal diffs over a persistent WebSocket connection. When a user types into the search box on the export screen, a filter event fires on the server, re-queries the database with the new search term and category filter, and sends back only the changed HTML. The user sees instant results. The developer wrote zero JavaScript.

This matters enormously for SceneSKU specifically because filtering scene packs by category, searching by title, paginating results, and managing multi-select state — all of this happens entirely on the server, across a handful of event handlers. The experience feels like a single-page app. The code reads like straightforward server logic.

The SEO benefit is real and practical. Public pack pages and the marketing site render as plain HTML on first load. There’s no client-side hydration step, no waiting for JavaScript to populate content. Google’s crawlers see the full page immediately. For a product that lives and dies by people finding specific scene categories, that’s not a nice-to-have.


Ash Framework: Stop Writing Boring CRUD Code

Most of the code I would have written by hand in any other stack simply doesn’t exist in SceneSKU, because Ash wrote it.

Ash is a declarative resource framework. Instead of writing controllers, changesets, query builders, and authorization checks as separate imperative steps, you declare a resource — what it is, what actions it allows, and who can do what — and Ash handles the implementation. The ScenePack resource illustrates this perfectly. It has a full lifecycle state machine: draft → planning → anchor generating → anchor ready → generating remaining → completed (or failed, cancelled, partially completed). Each state transition is a named action. The valid transitions are declared in one place, enforced at the data layer, and impossible to bypass.

Three concrete wins:

Instant stats without SQL gymnastics. Knowing how many images a pack contains, tracking total credits used, surfacing product data status — these are calculations that in a traditional stack require either denormalized columns maintained by hand or JOIN-heavy queries wrapped in service objects. In Ash, aggregate calculations live on the resource definition itself. The query engine handles the SQL. I declare what I want; Ash figures out how to retrieve it.

Admin interfaces for free. A single line in the router mounts a generated admin UI that covers every resource I’ve defined — scene packs, users, API keys, billing records, generation jobs. In a Node.js project, this requires installing and configuring a separate admin framework, then keeping it synchronized with your schema changes. In SceneSKU, it reads everything from the resource definitions that already exist.

Authorization that lives with the data. Every Ash resource carries its own policy block. ScenePack enforces that public packs are readable by anyone, private packs are readable only by their owner, and only the owner can update or delete their own packs — with admins bypassing all of this via a single rule at the top. These policies apply regardless of how the data is accessed: through a LiveView event, through the REST API controller, or from inside a background worker. There is one source of truth. Forgetting to add an authorization check to a new route doesn’t create a security hole, because the data layer refuses unauthorized access regardless.


Heavy Workflows Without the Overhead

SceneSKU generates multi-format CSV exports — Shopify, WooCommerce, and MedusaJS-compatible — covering every product variant, option value, image URL, SEO metadata, and pricing detail across however many packs a user selects.

In Node.js or Ruby, a large export blocks the web server process. The standard fix is to offload the work to Redis and Sidekiq or BullMQ, which means deploying and operating those services from day one.

Elixir sidesteps this entirely. Each web request runs in its own lightweight BEAM process. When a user triggers an export, that process does the work — loading packs, transforming data row by row, building the CSV in memory — completely isolated from every other user’s session. If one user’s export is processing 200 packs with 800 product images, the user loading the homepage next to them sees zero degradation. The BEAM scheduler handles this transparently.

For downloading pack assets — fetching images from object storage to bundle into a zip file — the code runs concurrent fetches with a controlled concurrency ceiling and built-in back-pressure, without a single external dependency. The whole thing runs comfortably on a modest VPS.

There is no Redis. There is no job queue server. Oban (a PostgreSQL-backed job queue library built for Elixir) handles background image generation workers — but it uses the same Postgres database that’s already there, with no additional infrastructure required.


Embrace the Cohesive Stack

The honest answer to the Reddit question is this: Elixir’s community psychology is neither “install everything” nor “build everything.” It’s design systems where each concern has exactly one home.

SceneSKU has a dozen background workers managing AI generation pipelines, webhook ingestion, image storage, and notification dispatch — all running as supervised BEAM processes. It has a public API with API key authentication, rate limiting, and OpenAPI documentation. It has a full state machine managing the pack generation lifecycle. It handles billing webhooks from Paddle. It serves 900+ high-fidelity product scene packs. One developer. One server.

If you’re building a SaaS as a solo developer, the most dangerous thing you can do is adopt an architecture designed for a 20-person engineering team because it’s what you see on tech Twitter. The fragmentation tax compounds. Every additional service is another thing to monitor, deploy, and debug at 2am when something breaks.

Pick the cohesive stack. Move fast. End up with something robust.

That’s vibe coding with Elixir.


Want to see the result? SceneSKU is live and free to try. Browse 900+ high-fidelity product scene packs, export structured mock data in Shopify, WooCommerce, or MedusaJS format, and get your demo store looking real in minutes.

Browse Scene Packs →

Create a free account →