From empty folder to live paying product in 48 hours
By Thomas · 2026-04-17
~30 min
Most weekend SaaS projects fail before the first line of code. Not because the code is hard. Because the idea is wrong.
A weekend SaaS needs three traits to succeed.
Narrow scope. One user type. One core action. You should be able to describe the whole product in a sentence. If you need a paragraph, the scope is too wide.
Real willingness to pay. Someone you can name would pay five to twenty a month for this. Not hypothetically. Actually.
Minimal external dependencies. No complex integrations that require API approvals taking weeks. No regulatory compliance layers. No hardware. Just web app, database, payments, email.
For this tutorial, we are building a simple SaaS I actually shipped. An invoice generator for solo freelancers. Users enter client info and line items, export a PDF, get a link to send the client. Free tier gives three invoices a month with a watermark. Pro tier at seven dollars a month removes the watermark and gives unlimited invoices.
Narrow scope: one user, freelancers. One core action: make an invoice. Willingness to pay: yes, every freelancing forum has complaints about invoice software being bloated. Dependencies: none.
You can follow this tutorial with my exact idea or substitute your own. The steps are identical. The specifics of your business logic will differ.
Spend thirty minutes now defining your idea this clearly. Write it down. If you cannot write it down in ten lines, keep refining until you can.
~45 min
The prompt is the most important hour of your weekend. Rushing here costs you Saturday.
Open a text file. Write it like this.
Section one, the user.
This tool is for solo freelancers who invoice between three and ten clients per month. They are not accountants. They want to generate professional invoices quickly without learning software.
Section two, the core loop.
User logs in. Sees a list of past invoices. Clicks New Invoice. Enters client name, client email, their own business info (cached from profile), line items (description, quantity, rate). Tool calculates subtotal, tax, total. User clicks Generate. Gets a PDF download and a shareable link.
Section three, the data model.
Users have a Profile (business name, business email, business address, tax number, default tax rate). Users have Clients (name, email, address). Users have Invoices. Invoices have many LineItems. Invoices have a status (draft, sent, paid). Invoices have a total calculated from line items plus tax.
Section four, the stack.
Next.js 15, TypeScript strict, Tailwind, Clerk auth, Supabase database, Stripe for subscriptions, Resend for email. Deploy to Cloudflare Pages.
Section five, the pages.
The home page for logged-in users shows a list of invoices grouped by status, a prominent New Invoice button, and a stat showing total invoiced this month.
The invoice creation page has a two-column layout. Left column is the form for entering data. Right column is a live preview of the invoice updating as the user types. Bottom of the page has a Generate button that creates the PDF and navigates to the success page.
The invoice view page shows the rendered invoice, a Download PDF button, a Copy Link button, and status controls (mark as sent, mark as paid).
The pricing page shows two tiers side by side. Free tier, three invoices a month, watermark. Pro tier, seven dollars a month, unlimited invoices, no watermark, custom branding.
Section six, non-negotiables.
Must not use dark navy backgrounds. Must use next/image for all images. Must await params in all dynamic routes. All forms must use server actions, not client-side fetch. All auth-protected routes must verify auth server-side, not just in middleware.
That is roughly 400 words of prompt. Resist the urge to add more detail. Let the model infer the rest.
Open CONTENTFORGER. Paste the prompt. Wait for the generation to complete. With Sonnet on Pro tier, expect two to three minutes.
When it is done, download the ZIP. Extract somewhere clean. Open in your editor.
You now have a complete Next.js 15 project. Auth scaffold, Supabase migrations, Stripe integration, the pages described. It will not be perfect. It will be ninety percent there.
~60 min
Before deploying, get it running on your machine. This catches the obvious issues early.
Open the project. Rename .env.example to .env.local.
You need to fill in values for every variable listed. Here is the minimum set for this SaaS:
Clerk publishable key and secret key. Create a free Clerk account. Go to API Keys. Copy both.
Supabase URL and anon key. Create a free Supabase project. Go to Settings, API. Copy the project URL and anon key. Also copy the service role key for server-side operations.
Stripe publishable and secret keys. Create a Stripe account if you do not have one. Start in test mode. Copy both keys from Developers, API keys.
Resend API key. Create a free Resend account. Copy the key.
Save .env.local. This file never commits to git. Confirm it is in .gitignore.
Run the setup commands. If the project uses pnpm (check for pnpm-lock.yaml), use pnpm. Otherwise npm.
pnpm install
Now set up the database. CONTENTFORGER includes migration SQL in a migrations folder. Open Supabase SQL Editor. Copy the migration file contents. Paste and run.
Supabase should now have your tables. Verify by going to Table Editor. You should see users, profiles, clients, invoices, line_items.
Run the dev server.
pnpm run dev
Open localhost:3000. You should see the landing page.
Click Sign Up. Create an account. You should be redirected to the dashboard. It will be mostly empty.
If any of these steps fail, check the server logs. The most common issues at this stage:
Missing env variable. The error usually says which one. Add it and restart.
Clerk webhook not configured for local dev. The user gets created in Clerk but not in your Supabase users table. Fix by manually inserting a row in Supabase users with the Clerk ID, or set up the Clerk webhook with ngrok for local testing.
Supabase migration failed silently. Go to Supabase SQL Editor, re-run the migration, check for errors in the response panel.
Once you can sign up and see the dashboard, you have a working local setup. This probably took forty-five minutes. Normal.
~45 min
Before deploying, verify the core loop actually works.
Click New Invoice. Fill in client details. Add two line items. Click Generate.
Does it produce a PDF. Does the PDF look reasonable. Does it appear in the invoice list.
Probably not. CONTENTFORGER output gets you ninety percent. The last ten is you.
Common issues at this stage:
PDF generation uses a library that needs specific setup. Look at the server logs. If it complains about missing binaries, you may need to add @vercel/og or a pdf-lib import. CONTENTFORGER usually picks a library but sometimes picks one that needs extra deps.
The preview does not update in real time as the user types. This is a React rerender issue. Usually a missing key on the line items array or a form state bug. Ten minutes to fix.
Tax calculation is wrong. CONTENTFORGER may have set up a simple tax calculation that ignores your profile's default tax rate. Fix the form to pull the rate from the profile.
Fix each issue as it appears. Do not add new features. Only fix the core loop. You want one user to be able to sign up, create an invoice, download the PDF.
Once that works end to end, you are ready to deploy.
This stage is where weekends get lost. People fix five things, get excited, start adding features, never ship. Discipline. Core loop only. Everything else after launch.
~30 min
The core loop works. Now add payments so you can actually charge for Pro.
In Stripe dashboard (still in test mode):
Create a product called Pro Plan. Price, seven dollars, recurring monthly. Copy the Price ID.
Add to your .env.local:
STRIPE_PRO_PRICE_ID=price_1Abcd...
In Stripe dashboard, go to Developers, Webhooks. Add endpoint. For now, skip the URL step, we will add it after deploy.
The CONTENTFORGER output already has /api/webhooks/stripe/route.ts wired up. You just need to point Stripe at it once deployed.
Restart your dev server. Go to the pricing page in your app. Click Upgrade to Pro. Stripe Checkout should open. Use test card 4242 4242 4242 4242.
Complete checkout. You should be redirected back to your app. Your account should show as Pro.
If the upgrade does not happen, the webhook is not firing (since we have not deployed yet). For now, manually update the user plan in Supabase. We will wire the webhook properly after deploy.
Test that Pro features work. Create an invoice. The watermark should be gone on Pro accounts.
You now have a working SaaS locally. Authentication, a functional product, a pricing tier that unlocks features. Time to deploy.
~60 min
Push to GitHub first.
git init git add . git commit -m "initial shippable version"
Create a new repo on GitHub. Push.
git remote add origin https://github.com/you/your-saas git branch -M main git push -u origin main
Install the Cloudflare adapter.
pnpm add -D @cloudflare/next-on-pages
In package.json add:
"scripts": { "pages:build": "npx @cloudflare/next-on-pages" }
Commit and push.
In Cloudflare dashboard, Workers and Pages, Create, Pages, Connect to Git.
Select your repo. Build settings:
Framework preset: Next.js Build command: pnpm run pages:build Build output: .vercel/output/static
Environment variables: add every variable from .env.local. Every single one.
Save and deploy.
First build takes three to five minutes. Watch the log.
Common deploy failures:
Missing env variable. The build log will say which one. Add it and retry.
Node version too old. Add NODE_VERSION=20 to env vars.
pnpm not found. Cloudflare usually auto-detects, but if it fails, change build command to "npm install -g pnpm and pnpm run pages:build" or use npm instead.
Once the deploy succeeds, you get a .pages.dev URL. Visit it. Your SaaS is live.
Now update Stripe and Clerk to point at your live URL.
Stripe: go to Webhooks, add endpoint. URL is your-site.pages.dev/api/webhooks/stripe. Select events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed. Copy the signing secret. Add to Cloudflare env vars as STRIPE_WEBHOOK_SECRET.
Clerk: in Clerk dashboard, go to Domains. Add your .pages.dev domain. Update redirect URLs to point at your live URL.
Redeploy Cloudflare to pick up the new env vars. Another three minutes.
Test the live site. Sign up with a fresh email. Check that the Clerk webhook fires and creates a Supabase user. Click upgrade to Pro, do test checkout, verify the Stripe webhook upgrades your account.
If everything works, you have a live, functional SaaS. On a free hosting plan. This is end of Saturday.
~30 min
The .pages.dev URL is fine for testing. For real customers, you want a real domain.
Buy a domain. Porkbun, Cloudflare Registrar, Namecheap are all fine. For this tutorial, let us say you bought quickinvoice.so.
If you bought through Cloudflare Registrar, skip the DNS step.
Otherwise, in your domain registrar, point nameservers to Cloudflare. Instructions vary by registrar but take five minutes.
In Cloudflare Pages, go to your project, Custom Domains, Set up a custom domain. Enter quickinvoice.so.
Cloudflare configures DNS automatically if you use Cloudflare Registrar. Otherwise it gives you the records to add manually.
Within an hour (usually ten minutes), your site is live on quickinvoice.so.
Update Clerk again to include the new domain. Update Stripe webhook URL to use the new domain.
Do one final test on the real domain. Sign up, create an invoice, upgrade to Pro. If all three work, you are done with infrastructure.
~60 min
Time to flip to live Stripe mode.
In Stripe dashboard, toggle from Test to Live.
Create your product again in live mode. It is separate from test. Note the new Live Price ID.
Create a live webhook endpoint pointing at your real domain. Copy the new signing secret.
Update your Cloudflare env vars:
STRIPE_SECRET_KEY to the new live secret key. NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY to the new live publishable key. STRIPE_PRO_PRICE_ID to the live Price ID. STRIPE_WEBHOOK_SECRET to the new live signing secret.
Redeploy.
On the live site, test with a real card for the cheapest possible amount. If you can, temporarily create a one-dollar product, buy it, confirm it works, then refund yourself.
Once confirmed, delete the test product. Keep your Pro Plan live.
Your SaaS is now accepting real payments.
Final steps.
Set up monitoring. Cloudflare has basic analytics. For error monitoring, add Sentry if not already in your CONTENTFORGER output.
Set up email deliverability. If using Resend, configure SPF and DKIM for your domain. Takes ten minutes.
Write a Terms of Service and Privacy Policy. CONTENTFORGER output usually includes placeholders. Fill them in. For a simple SaaS, terms and privacy boilerplate from iubenda or a similar service is fine.
Announce on one channel. Your Twitter, a relevant subreddit, Hacker News show HN. Do not spam ten places. Pick one where your user lives and post there. Include the URL, a screenshot, and a short description.
If your idea and execution are right, you will get first users within hours.
~20 min
What you just accomplished.
You went from empty folder to live SaaS accepting real payments. In about two days of work. With maybe fifty dollars of SaaS tool costs if you were on the free tiers throughout.
Five years ago, this took a team.
What worked.
Narrow scope. You picked one thing and only built that.
Fixing core loop before adding features. You stayed ruthless about what was blocking launch vs what was nice to have.
Using CONTENTFORGER's output as a starting point instead of a final product. You reviewed, fixed, and shipped. You did not treat the generated code as sacred.
Free tiers all the way. Cloudflare Pages, Supabase free, Clerk free, Resend free. Total cost to ship: your CONTENTFORGER Pro subscription plus whatever you spent on the domain.
What to do next.
Watch your first users. Every complaint is a todo item. Every feature request that three people ask for, build it. Every feature request only one person asks for, ignore it for now.
Iterate on the signup flow. The first version you shipped is fine. The version you ship next month will convert better.
Consider content. One SEO article a week takes hours. Over six months that is 25 articles ranking for invoice-related keywords. Free traffic compounds.
What not to do.
Do not rebuild from scratch. You will feel the urge to rewrite now that you know more. Resist. Iterate on what you have.
Do not add payment tiers until you need them. Free and Pro is enough for most SaaS projects for the first year.
Do not chase features that first users did not ask for. Let the users tell you what is missing.
Ship again next weekend.
Now that you have the process, the next SaaS takes less time. Second one in a day. Third in half a day. This is the real value of CONTENTFORGER and the weekend SaaS approach.
Some of them will work. Most will not. That is fine. The ones that work pay for the CONTENTFORGER subscription and then some.
Go ship.