Tazcreates

Tazcreates is the commission site for Tazmeen Zabiyaan, a portrait artist based in Canada working in acrylic, oil pastel, and ink. It is one page — gallery, pricing, process, FAQ — ending in a commission form that is a public endpoint anyone can post to, deployed on Cloudflare Workers under a 3 MiB free-plan script budget.

Client
Tazcreates
Timeline
2026
Role
Full-Stack Engineer
gzipped removed from the Worker payload
820 KBgzipped removed from the Worker payload
reduction in compiled script size
21%reduction in compiled script size
free-plan Workers script limit
3 MiBfree-plan Workers script limit
checks before an email is sent
5checks before an email is sent

Key takeaways

  • Cloudflare Pages could not host this site: @cloudflare/next-on-pages is deprecated and does not support Next 16, so the build moved to @opennextjs/cloudflare on Workers.
  • Rendering the social card once at build time into public/og.png removed 820 KB gzipped from the Worker payload, because next/og pulls resvg.wasm and yoga.wasm into the runtime graph.
  • The commission endpoint runs five checks — schema parse, honeypot, per-IP rate limit, server-side Turnstile verification, then send — before any email leaves, and the recipient address is always read from the environment rather than the request body.
Screenshot of Tazcreates — Next.js 16, TypeScript, Tailwind CSS v4 project by Shafin Ahmed

The problem

A commission form is the whole business case for an artist's site, and it is also the part that attracts abuse: it is a public endpoint that spends money on every send and can be pointed at arbitrary recipients if it is written carelessly. The deployment added a second constraint. The original Cloudflare Pages build failed outright — @cloudflare/next-on-pages is deprecated and has no Next 16 support — and the Workers plan that replaced it caps a compiled script at 3 MiB gzipped, which the first build exceeded.

The approach

The site migrated to @opennextjs/cloudflare, which compiles the Next output into a Worker plus a static asset directory. Getting under the script limit was a measurement exercise, not a guess: deleting unreachable files moved the payload zero bytes because Next never bundled them, while moving the social card out of next/og and into a build-time script removed 820 KB. Static assets are served from Cloudflare's asset store and do not count against the limit. The commission route re-parses every submission against the same Zod schema the form uses, treats a filled honeypot as a silent success so bots learn nothing, rate-limits per IP before spending a Turnstile call, verifies the captcha token server-side and fails closed on a verification outage, and only then sends — always to the configured address, never to one supplied in the payload.

What it does

  • Single-page build: hero, masonry gallery with lightbox, pricing tiers, commission process, FAQ
  • Commission form validated by one Zod schema shared between the client and the API route
  • Honeypot, per-IP rate limit, and server-verified Cloudflare Turnstile in front of every send
  • Resend + React Email delivery, with a best-effort confirmation back to the visitor
  • Reduced-motion-aware marquee and scroll reveals
  • Server-rendered JSON-LD and a build-time Open Graph card
  • Deployed to Cloudflare Workers via OpenNext, with the custom domain pinned in wrangler.jsonc

Stack

Next.js 16TypeScriptTailwind CSS v4Cloudflare WorkersOpenNextResendCloudflare Turnstile

Outcome

Compiled Worker script reduced 21%, from 3,833,495 to 3,013,678 bytes gzipped, fitting the 3 MiB free-plan limit

Commission requests reach the artist by email instead of only through Instagram direct messages

Deployed on Cloudflare Workers after the deprecated Pages adapter blocked the original build

References

Tazcreates — questions

Common questions about Tazcreates and how it was built.

Building something similar?

I'm open to new opportunities and project work.