DEV Community

Cover image for I Built a Free AI Background Remover with Next.js 16 & Cloudflare Workers — $0/mo
WobblyDev
WobblyDev

Posted on

I Built a Free AI Background Remover with Next.js 16 & Cloudflare Workers — $0/mo

Let me start with some context: I have a graveyard of unfinished side projects. Probably 15+ repos that never saw the light of day. This time I told myself — ship it, no matter how ugly the first version is.

The idea was dead simple. Upload a photo, remove the background, download a transparent PNG. That's it.

I ended up building imagesbackgroundremover.com — and the whole thing runs on Cloudflare's free tier. Zero dollars a month in hosting costs. I've also open-sourced the entire codebase so you can see exactly how it's put together:

GitHub logo turnturn / bg-remover-nextjs-cloudflare

Free AI Background Remover built with Next.js 16, Tailwind CSS 4, and Cloudflare Workers. Zero infrastructure cost.

🖼️ BG Remover — AI Background Remover

Remove image backgrounds instantly with AI. Free, fast, and no signup required.

🌐 imagesbackgroundremover.com

✨ Features

  • 🎯 AI Background Removal — Powered by advanced AI that detects subjects and removes backgrounds in seconds
  • 📸 Drag & Drop Upload — Supports JPG, PNG, and WebP (up to 10 MB)
  • 🔍 Before/After Comparison — Interactive slider to compare original and processed images
  • ⬇️ One-Click Download — Download transparent PNG with a single click
  • 📱 Fully Responsive — Works flawlessly on mobile, tablet, and desktop
  • 🌍 Multi-language — English and Chinese (中文) support
  • 🔒 Privacy First — Images are processed in real-time and never stored
  • 🔍 SEO Optimized — JSON-LD, Open Graph, Twitter Cards, semantic HTML, blog

🚀 Live Demo

Try it now at imagesbackgroundremover.com

How It Works

  1. Upload your image (JPG, PNG, or WebP)
  2. AI processes and removes the background automatically
  3. Download the transparent PNG…

Here's the honest breakdown of how it went.


The architecture (kept it boring on purpose)

I'm a big believer in boring technology. The fewer moving parts, the fewer things that break at 2am.

The whole system is just a browser talking to Cloudflare Workers on the edge. No origin server, no Docker containers, no Kubernetes, no "microservice mesh." Workers handles routing, auth, and API calls. Data goes to D1 and KV. That's it.

Architecture diagram

The "boring" architecture: browser → Cloudflare Workers → D1/KV, with Google OAuth and PayPal as external services.

Here's the stack in plain terms:

  • Next.js 16 — App Router with Edge Runtime. The latest version, because why not live on the edge (pun intended).
  • TypeScript — I don't write JS without types anymore. Life's too short for undefined is not a function.
  • Tailwind CSS 4 — Say what you will, but I can prototype a decent-looking UI in hours instead of days.
  • Cloudflare Workers — The compute layer. Deployed via opennextjs-cloudflare (see the config).
  • D1 — Cloudflare's edge SQLite. Stores users, credits, transactions.
  • KV — Key-value store for sessions. Think Redis, but free and managed.
  • Google OAuth — Login. Hand-rolled, not NextAuth (more on this later).
  • PayPal — Payments. Subscriptions and one-time credit packs.

Monthly infrastructure cost: $0. Not "$0 for the first 3 months." Just $0.


Why I left Vercel

I know, I know. "Next.js + Vercel" is like peanut butter and jelly. And honestly, the developer experience on Vercel is excellent.

But here's what happened. I needed a database for users and credits. I needed session storage. On Vercel's free tier, that means bolting on external services — a hosted Postgres, maybe Upstash for Redis. Suddenly my "free" project had $15-20/month in dependencies.

Cloudflare gave me all of that for free:

  • D1 — A real SQL database at the edge. Not a toy. Actual SQLite with proper query support.
  • KV — Session storage without managing Redis.
  • No cold starts — Workers are always warm. Users in Tokyo and users in Berlin get the same fast response.

The catch? You need opennextjs-cloudflare to make Next.js work on Workers. It's an adapter, and it works — but don't expect the Vercel-level polish. Debugging runtime errors on Workers can feel like reading tea leaves sometimes.

For a solo project with zero budget, the math was obvious.


The deploy gotcha that cost me an afternoon

Let me save you some time: pushing to GitHub does NOT trigger a Cloudflare Workers build.

If you've used Cloudflare Pages, you're probably expecting Git-push deploys. Workers doesn't do that. You need two commands:

npx opennextjs-cloudflare build   # ~45 seconds
npx wrangler deploy               # ~45 seconds
Enter fullscreen mode Exit fullscreen mode

Deployment pipeline

The deploy flow: two commands, under 2 minutes from commit to live.

I spent a genuinely embarrassing amount of time refreshing my production URL and wondering why nothing changed. Don't be me.

Also, in your wrangler.toml, do not forget this line:

compatibility_flags = ["nodejs_compat"]
Enter fullscreen mode Exit fullscreen mode

Without it, Node.js APIs that Next.js depends on will fail silently at runtime. Not with a nice error message. Just weird, broken behavior that makes you question your life choices.


The UI: one rule

I gave myself one rule for the interface: if someone can't figure out what this tool does within 5 seconds, I failed.

So the design is deliberately simple. Upload area dead center. Three-step "how it works" below. FAQ at the bottom. No sidebar, no feature tour, no "watch our 2-minute intro video." Just the thing you came here to do.

Product screenshot

The live product — one page, one action, zero confusion.

The before/after slider

This is probably my favorite piece of UI in the whole project. It looks like it needs a fancy library, but it's actually embarrassingly simple:

Click to see the slider code (React + CSS clip-path)
<div className="relative overflow-hidden">
  <img src={originalUrl} alt="Original" />
  <img 
    src={processedUrl} 
    alt="Processed"
    style={{ clipPath: `inset(0 ${100 - position}% 0 0)` }} 
    className="absolute inset-0"
  />
  <input 
    type="range" min={0} max={100} 
    value={position}
    onChange={(e) => setPosition(Number(e.target.value))}
  />
</div>
Enter fullscreen mode Exit fullscreen mode

That's it. CSS clip-path and a native range input. No npm package needed.

i18n for two languages

The site supports English and Chinese. I considered next-intl and react-i18next, then decided they were massive overkill for two languages. Instead I wrote a simple i18n.ts:

export type Locale = "en" | "zh";

export const messages: Record<Locale, Messages> = {
  en: {
    hero: { title: "Make your images clean, cut-out, and ready to use." },
  },
  zh: {
    hero: { title: "让图片更干净,更利落,更适合直接使用。" },
  },
};
Enter fullscreen mode Exit fullscreen mode

Language switching uses ?lang=zh URL params with localStorage persistence. An applySeo() function updates all meta tags dynamically.

Is this the "right" way to do internationalization? No. Does it work perfectly for my use case? Absolutely.


Auth: 200 lines vs. a framework

I hand-rolled Google OAuth instead of reaching for NextAuth. Here's why:

  1. I only need Google login. NextAuth is built for "sign in with 47 different providers." That's not my problem.
  2. Edge compatibility. Some NextAuth adapters don't play nice with Workers.
  3. It's three routes. That's it.
/api/auth/login           → redirect to Google consent screen
/api/auth/callback/google → exchange code for tokens, create user in D1
/api/auth/me              → look up session in KV, return user
Enter fullscreen mode Exit fullscreen mode

Sessions live in KV with a 7-day TTL. The entire auth system is ~200 lines. Sometimes the best abstraction is no abstraction.


Making money (the honest version)

I went with a credits model because it's the simplest thing that could work:

Plan Price What you get
Free $0 3 credits on signup
Starter $3.49/mo 10 credits/month
Pro $8.69/mo 25 credits/month
Credit Pack (5) $1.73 Never expire
Credit Pack (10) $3.46 Never expire

PayPal handles subscriptions and one-time purchases. The integration was fine until I hit webhook signature verification. PayPal's documentation for verifying webhooks on edge runtimes reads like it was written by someone who has never actually tried to verify a webhook on an edge runtime. I got it working eventually, but it was not fun.


SEO for a domain that Google has never heard of

A brand-new domain has zero authority. Zero. Google doesn't know you exist, and it doesn't care that your code is clean.

Here's what I did:

The basics (one afternoon of work):

  • Proper robots.txt and sitemap.xml
  • JSON-LD structured data (WebApplication schema)
  • Open Graph + Twitter Card tags
  • Canonical URLs and hreflang for both languages
  • Title < 70 chars, description < 155 chars

The real work (ongoing):

  • Built a /blog with three articles targeting long-tail keywords:
    • "How to Remove Image Background for Free in 2026"
    • "Best Background Remover Tools Compared"
    • "Transparent PNG for Ecommerce Product Photos"
  • Each post has its own SEO metadata, JSON-LD Article schema, canonical URL, and a CTA back to the main tool

Technical SEO is table stakes. Everyone has it. Content and backlinks are what actually move the needle — and that's a game measured in months, not days.


Five things I'd tell past-me

1. Ship the smallest version first. My v1 had no login, no payments, no blog. Just: upload → remove → download. One page, one button. I added everything else after confirming people actually used it.

2. Cloudflare's free tier is a cheat code. D1 + KV + Workers replaces $20-30/month of managed services. For indie devs and side projects, this changes the economics completely.

3. Don't fight the deployment. I wasted time trying to get Git-push deploys working with Workers. Just accept the two-command flow and move on.

4. Resist every feature idea. I almost added batch upload, color backgrounds, AI enhancement filters. Glad I didn't. The product is better because it does one thing well.

5. SEO is a slow burn. The technical foundation matters, but don't expect Google to notice you for weeks. Write content, build links, be patient.


Try it

If you need to remove a background from an image — give it a spin. Free, instant, no signup required, works on mobile.

Try the Background Remover for Free

The full source code is open:

GitHub logo turnturn / bg-remover-nextjs-cloudflare

Free AI Background Remover built with Next.js 16, Tailwind CSS 4, and Cloudflare Workers. Zero infrastructure cost.

🖼️ BG Remover — AI Background Remover

Remove image backgrounds instantly with AI. Free, fast, and no signup required.

🌐 imagesbackgroundremover.com

✨ Features

  • 🎯 AI Background Removal — Powered by advanced AI that detects subjects and removes backgrounds in seconds
  • 📸 Drag & Drop Upload — Supports JPG, PNG, and WebP (up to 10 MB)
  • 🔍 Before/After Comparison — Interactive slider to compare original and processed images
  • ⬇️ One-Click Download — Download transparent PNG with a single click
  • 📱 Fully Responsive — Works flawlessly on mobile, tablet, and desktop
  • 🌍 Multi-language — English and Chinese (中文) support
  • 🔒 Privacy First — Images are processed in real-time and never stored
  • 🔍 SEO Optimized — JSON-LD, Open Graph, Twitter Cards, semantic HTML, blog

🚀 Live Demo

Try it now at imagesbackgroundremover.com

How It Works

  1. Upload your image (JPG, PNG, or WebP)
  2. AI processes and removes the background automatically
  3. Download the transparent PNG…




Got questions about the edge deployment, the OAuth flow, or anything else? Happy to go deeper in the comments.

Top comments (1)

Collapse
 
mecloud profile image
mecloud

👍️