Building iBuildElementor: Productizing a Service Business
How I pivoted from hourly freelancing to a productized service. Deep dive into the Next.js/Supabase portal I built to manage it and the lessons on scaling.
I hit a wall. A hard one.
It wasn't a technical wall. It wasn't that I didn't know how to code or that I couldn't configure a server. The wall was time. There are only 24 hours in a day and I was selling every single one of them. If I stopped typing, the money stopped flowing.
That is the freelance trap.
You start out loving the freedom. You can work from anywhere - heck, I’m in Ireland now doing my Masters in Cloud Computing and I can still work. But eventually, you realize you haven't bought freedom. You've just bought a job where the boss is a dozen different clients who all think everything is "urgent."
I needed a way out. I needed to decouple my time from my income. But I wasn't ready to launch a full-blown SaaS product from scratch just yet. I needed a bridge.
That bridge was iBuildElementor.
The idea was simple: Productize the service. Take what I was doing manually and bespoke for everyone, wrap it in a box, put a fixed price tag on it, and sell it like a product.
Here is how I built it, the tech stack I used to manage it, and why productizing a service is the best crash course in systems engineering you will ever get.
The Psychology of "The Box"
The hardest part wasn't the code. It was the definition.
When you are a freelancer, you are a "Yes Man."
"Can you fix my email server?" Yes. "Can you design a logo?" Yes. "Can you tweak this CSS?" Yes.
To productize, you have to become a "No Man."
iBuildElementor does one thing: We take your Figma or Adobe XD design and turn it into a pixel-perfect Elementor website. That's it.
We don't design. We don't write copy. We don't do SEO audits. We convert design to code.
By drawing this hard line in the sand, I removed the biggest variable in software estimation: Scope Creep. Because the input (the design file) is fixed, the output is deterministic. I could look at a design and know exactly how long it would take to build, down to the minute.
This predictability is what allows you to scale. You can't scale chaos.
The Tech Stack: Managing the Factory
I didn't want to manage this via email. Email is where productivity goes to die. I wanted a system.
Since I'm pivoting heavily into modern Cloud and SaaS architectures, I decided to build a custom client portal to manage iBuildElementor orders. I used this as a playground to sharpen my skills with Next.js, Tailwind CSS, and Supabase.
This wasn't just a "contact form." This was an order management system.
The Database Schema
I needed a way to track orders, status, and file assets. Supabase (PostgreSQL) was perfect for this. I set up a simple relational schema.
Here is a stripped-down version of how I handled project states in the database. I used TypeScript Enums to keep things strict on the frontend and backend.
// types/database.ts export enum ProjectStatus { PENDING_REVIEW = 'pending_review', AWAITING_ASSETS = 'awaiting_assets', IN_DEVELOPMENT = 'in_development', QA_PHASE = 'qa_phase', COMPLETED = 'completed', CANCELLED = 'cancelled' } export interface Project { id: string; user_id: string; project_name: string; figma_link: string; status: ProjectStatus; created_at: string; price_quote: number | null; deadline: string | null; }
Using Supabase, I could leverage Realtime subscriptions. This meant when I updated a project status from "In Development" to "QA Phase" on my admin dashboard, the client's dashboard updated instantly without them needing to refresh.
It’s a small touch, but it screams "professional software" rather than "freelancer hacking things together."
The Order Flow (Next.js Server Actions)
I used Next.js 14 with Server Actions to handle the submission logic. This keeps the client-side code clean and secure. I didn't want to expose any API keys or logic to the browser.
Here is how I handled a new project submission. Note the validation. In a productized service, validation is everything. If the input is bad (like a broken Figma link), the whole factory line stalls.
'use server' import { createClient } from '@/utils/supabase/server' import { revalidatePath } from 'next/cache' import { z } from 'zod' const OrderSchema = z.object({ projectName: z.string().min(3), figmaLink: z.string().url().includes('figma.com'), notes: z.string().optional() }) export async function submitOrder(formData: FormData) { const supabase = createClient() // Auth check first. Always. const { data: { user } } = await supabase.auth.getUser() if (!user) throw new Error('Unauthorized') const rawData = { projectName: formData.get('projectName'), figmaLink: formData.get('figmaLink'), notes: formData.get('notes') } const result = OrderSchema.safeParse(rawData) if (!result.success) { return { error: 'Invalid data. Please check your Figma link.' } } const { error } = await supabase .from('projects') .insert({ user_id: user.id, project_name: result.data.projectName, figma_link: result.data.figmaLink, status: 'pending_review' }) if (error) return { error: error.message } revalidatePath('/dashboard') return { success: true } }
This simple action handles authentication, validation, and database insertion in one go. It’s fast, secure, and type-safe.
Standardizing the Output (The SOPs)
Productization fails if the execution varies. If I build the site one way, and a junior dev I hire builds it another way, the product is broken.
I had to document everything.
I created a "Base Stack" for every project. We didn't just install WordPress and wing it. We had a starter blueprint:
- Hello Elementor Theme: Lightweight, no bloat.
- ACF Pro: For custom data structures.
- Custom Plugin: I wrote a small internal plugin that deregistered unnecessary scripts and styles that WordPress loads by default.
Optimization was baked in. We didn't "optimize later." We started optimized.
For naming classes, I enforced a BEM-lite naming convention within Elementor’s custom CSS fields. This ensured that if a client came back six months later, I (or anyone else) could look at the code and know exactly what .hero__headline--primary was doing.
The Pricing Struggle
Pricing a productized service is scary.
With hourly billing, you have a safety net. If it takes longer, you charge more. With a fixed price, you eat the risk. If I quote $500 for a landing page and it takes me 20 hours because I messed up the estimation, I’m making $25/hour. That is not why I got into this game.
I adopted a "Tiered Complexity" model:
- Simple: Standard sections, standard layout. Fixed price.
- Complex: Animations, custom post types, dynamic filtering. Custom quote (but based on a fixed calculator).
The portal I built handled this. Clients would submit the request, the status would go to PENDING_REVIEW, and I would manually review the Figma file. I would then attach a price tag in the admin panel which would unlock the "Pay Now" button on their side.
It wasn't fully automated SaaS (yet), but it was streamlined service delivery.
Why I Am Still Moving to SaaS
iBuildElementor was a success. It stabilized my cash flow. It taught me how to manage a backlog and how to build internal tooling with the Next.js/Supabase stack I love.
But it still has a flaw: Human Labor.
Even with the best SOPs, someone still has to drag the widgets in Elementor. Someone still has to check mobile responsiveness on an iPhone. I can hire people to do that, but then I'm managing people.
My goal as an Indie Hacker and Cloud Engineer is to build systems where the software does the work, not the people.
Building iBuildElementor taught me that I enjoy building the system (the portal, the automation, the database schema) more than I enjoy doing the work (building the websites).
That realization is crucial.
It confirmed that my move into Cloud Computing and high-level software engineering is the right one. I want to architect the platforms that other people use to build businesses. I want to wrestle with AWS Lambda functions and scaling strategies, not padding issues on Safari.
The Cloud Angle
This experience directly informs how I approach Cloud Engineering now.
When I look at an AWS architecture, I don't just see services. I see a productized workflow.
- Lambda is the worker bee executing the SOP.
- S3 is the asset repository.
- DynamoDB is the order tracker.
The principles are identical. Whether you are managing a WordPress agency or a microservices architecture, the goal is the same: Decoupling. Decoupling components so they can scale independently, and decoupling your time from the system's output.
Final Thoughts
If you are stuck in the freelance grind, try productizing just one thing you do.
Don't offer "Web Development." Offer "One-Page React Landing Pages for $X."
Force yourself to define the boundaries. Build a system to handle the intake. It will force you to become a better engineer because you have to think about edge cases before they happen.
And for me? iBuildElementor runs smoothly in the background. It funds my tuition, it funds my experiments, and it buys me the time to build the next big thing.
Now, I'm going back to my code. I have a Supabase Edge Function that needs debugging.
Read Next
The Truth About 'Overnight Success' in Software
Viral success stories are edited truths. From WordPress veteran to Cloud Engineer, here is the reality of technical debt, the modern stack trap, and the long grind.
ReadHow to Launch a Product When You Have Zero Audience
Launching to crickets? Stop tweeting to nobody. Here is the engineer’s guide to leveraging code, programmatic SEO, and community hacking to build traction from zero.
Read