Aditya Deokar
TIME
// 01
HHoommee
→
// 02
WWoorrkk
→
// 03
AAbboouutt
→
// 04
BBlloogg
→
// Connect
LinkedIn↗
GitHub↗
X / Twitter↗

© Aditya Deokar // Portfolio

Elevated digital experiences

Back
Architecture
12 min read
January 15, 2025

I Built a Microservices Architecture, But I Couldn't Afford to Deploy It. Then I Found the Edge.

How I migrated my multi-service Express ecosystem to Cloudflare Workers & Hono.js to get a production-grade distributed system for $0.

A

Aditya Deokar

2.5K views

#Microservices#Cloudflare Workers#Hono.js#Serverless#Architecture#Edge Computing

I have a problem.

I don't build "Todo Lists" anymore. My GitHub isn't full of simple CRUD apps. I'm a student, but I build like a Senior Engineer. I design microservices. I separate my concerns. I have an Auth Service, a Product Service, and a Notification Service, all orchestrated by a Next.js frontend.

On my laptop (MacBook Air), this architecture is beautiful. I spin up Docker Compose, my 4 containers talk to each other, and it feels like magic.

But then comes the "Deployment Depression."

To host this architecture on AWS, I would need:

  1. 01.An Application Load Balancer (ALB) - $$$
  2. 02.ECS (Elastic Container Service) or multiple EC2 instances - $$$
  3. 03.A managed RDS database - $$$
  4. 04.A VPC NAT Gateway - $$$ (The silent killer)

I am a student. I cannot drop $60/month just to show a recruiter that I understand distributed systems. So, for the longest time, my best code sat in a private repo, never seeing the light of day.

I needed a way to deploy a complex, multi-service backend with zero cost, zero cold starts, and zero server management.

That is when I ditched containers for Cloudflare Workers and swapped Express for Hono.js.


The Realization: You Don't Need Containers

I used to think that to have microservices, I needed Docker. I was wrong.

Microservices are just about separation of concerns and independent deployment. You don't need a heavy Linux container to achieve that. You just need isolated runtime environments.

Cloudflare Workers provides exactly that. But writing raw Worker code is painful if you are coming from the Express.js world.

Enter Hono.js: The "Express" for the Edge

I love Express. I love the middleware pattern. When I found Hono.js, I realized I didn't have to relearn how to code. Hono is basically Express, but:

  1. 01.It runs on the Web Standard API (Request/Response), not Node.js.
  2. 02.It is 10x lighter.
  3. 03.It has TypeScript built-in.

I was able to port my Express services to Hono in roughly 30 minutes per service.


The Architecture: From Docker Compose to Service Bindings

Here is the coolest part. In my Docker setup, my services talked to each other over an internal network (e.g., http://auth-service:3000).

In Cloudflare, we have something even better called Service Bindings.

This allows one Worker (my API Gateway) to call another Worker (my Auth Service) directly without going over the public internet. It eliminates network latency and security risks.

The "Broke Student" Microservices Diagram

text
1Client (Next.js Frontend) 2 ↓ 3Gateway Worker (Hono) 4 ↓ 5 ├── Auth Worker (Hono) → D1 Database (SQL) 6 └── Product Worker (Hono) → Workers KV (Cache)

Cost for this setup: $0.

Scale: 100,000 requests/day (Free Tier).


The Code: How it actually looks

Here is how I structured my Gateway Service. Notice how it looks just like the Express code I was already writing, but it's calling other "services" via bindings.

The Gateway (Entry Point):

typescript
1import { Hono } from 'hono' 2import { cors } from 'hono/cors' 3 4// Define the types of the OTHER services we are calling 5type Bindings = { 6 AUTH_SERVICE: Fetcher; // This is the magic link to the other worker 7 PRODUCT_SERVICE: Fetcher; 8} 9 10const app = new Hono<{ Bindings: Bindings }>() 11app.use('/*', cors()) 12 13// Proxy request to Auth Service 14app.route('/auth', async (c) => { 15 // Instead of fetch('https://api.mysite.com/auth'), we do this: 16 return c.env.AUTH_SERVICE.fetch(c.req.raw) 17}) 18 19// logic composition example 20app.get('/dashboard', async (c) => { 21 // call auth service internally to validate token 22 const authRes = await c.env.AUTH_SERVICE.fetch('http://internal/validate', { 23 method: 'POST', 24 headers: c.req.header() 25 }) 26 27 if (authRes.status !== 200) return c.json({error: 'Unauthorized'}, 401) 28 29 // If auth passes, get products 30 const products = await c.env.PRODUCT_SERVICE.fetch('http://internal/list') 31 return c.json(await products.json()) 32}) 33 34export default app

The "Unpopular" Features (That Saved My Life)

Since I treat my projects like professional software, generic tutorials didn't cover my needs. Here are the advanced features of this stack that solved my specific "Senior Dev" problems:

1. Service Bindings (RPC for Free)

I cannot stress this enough. Most people deploy Monoliths on Cloudflare. But if you want Microservices, Service Bindings are the key.

  • Why it's great: It avoids the "Network Hop." When Worker A calls Worker B, it happens inside the Cloudflare data center. It's incredibly fast and costs one request billable, not two.

2. Cloudflare D1 (Real SQL, Finally)

One reason I stuck with containers was Postgres. I hated NoSQL "Key-Value" stores for complex data.

Cloudflare D1 is a serverless SQLite database. It supports joins, transactions, and foreign keys.

  • Student Win: It's free (up to 5GB storage in beta/free tiers). I can run my SELECT * FROM users JOIN orders queries without paying for RDS.

3. Monorepo Support with Wrangler Workspaces

I keep all my microservices in one GitHub repo (Monorepo) using Turborepo or simple npm workspaces.

Cloudflare's CLI (wrangler) supports workspaces natively.

  • Command: wrangler deploy (at the root).
  • Result: It detects all my services (Auth, Product, Gateway) and deploys them all at once.

4. Shared Logic Packages

Because Hono uses standard Web APIs, I created a shared-utils folder in my monorepo with my Zod validation schemas and TypeScript interfaces. I import this package into both my Next.js Frontend and my Hono Backend.

  • Result: End-to-End type safety. If I change the API response shape in the backend, my frontend build fails immediately.

Conclusion: Stop Paying for Idle CPU

As a student with a senior mindset, you know that architecture matters. But you also know that budget is a constraint.

By moving to Cloudflare Workers and Hono.js, I kept my microservices architecture. I kept my TypeScript. I kept my separation of concerns.

The only thing I lost was the monthly bill and the headache of managing Docker containers.

If you have a project stuck on your localhost because it's "too complex to host for free," try this stack. It's the only way to build "Big Tech" architecture on a "Broke Student" budget.

End of article12 min read