SaaS website builder

Forge.

A website builder that takes a small business from nothing to a published site in about five minutes, with the content dashboard, lead capture and analytics needed to keep using it afterwards.

Real running software. Build a site and it publishes immediately.No sign-up: the site is yours, live for seven days.

Sector

Small business, local services

Scope

Self-initiated product. Design, architecture, build, deployment

Stack

Next.js, TypeScript, PostgreSQL, Cloudinary

Team

Product design, backend, frontend, DevOps

01The situation

Context

A local gym, salon or cleaning company has three routes to a website. An agency quotes thousands and takes weeks. A drag-and-drop builder costs an evening and still looks like a template. The third route is no website at all, which is what most of them pick.

The thing that stops the second route working is not the editor. It is the blank page. A builder hands over an empty canvas and a library of blocks, and a plumber is now doing layout design at 9pm.

Forge starts from the trade instead. Pick your industry and the site arrives already written for it, with the sections that industry needs and copy that reads like a real business rather than placeholder text. Editing what is there is a much smaller task than inventing it.

02What made it hard

Constraints

It has to be free to run at zero traffic

A demo estate that costs money per idle site is a demo estate that gets switched off. The whole product had to sit inside a free hosting tier with no always-on server and no per-site cost.

No signup before value

Asking for an email before showing anything loses most of the people worth keeping. The wizard creates a real, working, published site first and only then mentions accounts.

Published sites must load fast for strangers

The visitor to a published site has no relationship with us and no patience. That ruled out any host that sleeps when idle, because the first visitor after a quiet hour would have waited a minute.

One tenant must never see another

Every site, section, lead and image belongs to exactly one owner, and the ids are sequential integers. Guessing a neighbouring id had to return nothing rather than someone else's enquiries.

03The build

What we built

01

Four-step build wizard

Industry, business details, template, palette. The preview updates as you type, the slug is derived from the business name, and the finished site is published at its own address before any account exists.

02

Content dashboard

Eight section types (hero, about, services, gallery, testimonials, pricing, FAQ, contact) each with a purpose-built editor rather than a generic block. Sections reorder by drag, hide individually, and the live site reflects a save immediately.

03

Lead capture

The contact form on a published site writes to the owner's dashboard with read and unread state, so an enquiry is a thing with a status rather than an email that gets buried.

04

Media manager

Drag-and-drop upload straight to a CDN, with deletion reconciled against the remote asset so removing an image actually removes it rather than orphaning the file and paying for it forever.

05

Visitor analytics

Page views over time, device and browser breakdown, and referrer sources, parsed from the request and aggregated per site. Enough for an owner to know whether the site is doing anything.

04How it fits together

Architecture

Frontend

Next.js App Router with TypeScript and Tailwind. A published site is a server component that reads the database directly, so rendering a visitor page is one query rather than an HTTP call the app makes to itself.

API

Route handlers inside the same Next application. There is no separate backend service, no second deployment to keep in step, and consequently no CORS surface at all.

Data

PostgreSQL on Neon, reached through the pooled endpoint because serverless instances scale out horizontally and would otherwise exhaust the connection limit. The pool is created on first query, never at import, so a build without credentials still succeeds.

Auth

Short-lived JWT access tokens with single-use refresh rotation. Passwords use bcrypt. Refresh tokens use SHA-256, because bcrypt truncates at 72 bytes and a JWT is longer than that.

Media

Uploads pass through the API to Cloudinary and are served from its CDN. Deletion derives the asset id from the stored key rather than the delivery URL, which carries a version segment that never matches.

Infra

One Vercel deployment for the whole product. No container, no always-on process, and nothing to pay for while sites sit idle. Schema migrations run as a script rather than on boot, so a cold start never races a DDL statement.

Next.js · TypeScript · PostgreSQL · Neon · Cloudinary · Tailwind CSS · ShadCN/UI · Vercel

05Why it is built this way

Key decisions

01

The API lives inside the frontend

Forge began as a separate API service alongside the site. Collapsing it into the Next application removed an entire class of failure: two deployments drifting apart, a frontend pointing at a backend URL that stopped existing, and CORS configuration that only breaks in the environment you cannot debug. It also made published pages faster, because the server reads the database instead of calling its own API over the network.

02

Serverless changes what a background write means

Recording a page view was originally fire-and-forget, which is correct in a long-lived process. On serverless the instance can be frozen the moment it responds, so those writes were being dropped silently and analytics would have undercounted without ever erroring. Anything that must survive the response is now awaited, and the tracking call is wrapped so a failure cannot break the page it is measuring.

03

Tenancy is enforced per row, not per route

Checking that the caller owns the site is necessary but not sufficient, because ids appear in the path for leads, sections and images too. Every single-record operation is scoped by site id in the query itself, so a guessed id returns 404 instead of another tenant's data. The route guard and the query both have to agree before anything is returned.

04

Guest sites expire, and that is the product

Every site built without an account carries a seven day life. It keeps the demo estate bounded, it makes the free hosting tier viable indefinitely, and it gives the person who built one a reason to talk to us. An expired site serves a page explaining what happened rather than a dead link.

06Capability

What this demonstrates

Multi-tenant isolation enforced at the query, not just the route

Content management with live preview and per-section editors

Session handling with single-use refresh token rotation

CDN media pipeline with lifecycle reconciliation

Analytics capture and aggregation, correct across time zones

A complete product deployed and operated at zero hosting cost