{"id":116,"date":"2026-07-21T12:45:00","date_gmt":"2026-07-21T07:15:00","guid":{"rendered":"https:\/\/softcrony.com\/blog\/?p=116"},"modified":"2026-07-21T12:45:00","modified_gmt":"2026-07-21T07:15:00","slug":"cloudflare-workers-edge-computing-india-guide","status":"publish","type":"post","link":"https:\/\/softcrony.com\/blog\/cloudflare-workers-edge-computing-india-guide\/","title":{"rendered":"Cloudflare Workers for Indian Developers: Edge Computing Practical Guide"},"content":{"rendered":"<p>Cloudflare Workers lets you run JavaScript at the network edge \u2014 in data centers physically close to your users, rather than in a central server. For Indian users, this means the difference between 400ms response times from a US server and 20ms from Cloudflare&#8217;s Mumbai or Chennai edge nodes.<\/p>\n<p>This guide covers what Cloudflare Workers actually is, when to use it, and how to build real things with it \u2014 specifically for Indian developers and businesses.<\/p>\n<h2>What Is Edge Computing?<\/h2>\n<p>Traditional web architecture: User in Jabalpur \u2192 Request travels to your server in Mumbai (or worse, Singapore\/US) \u2192 Response travels back. Round trip: 80\u2013400ms depending on server location.<\/p>\n<p>Edge computing: User in Jabalpur \u2192 Request hits Cloudflare&#8217;s nearest node (Mumbai, ~10ms away) \u2192 Code runs at the edge \u2192 Response served immediately. Round trip: 15\u201330ms.<\/p>\n<p>Cloudflare Workers is a serverless edge platform where your JavaScript\/TypeScript code runs in Cloudflare&#8217;s network of 300+ data centers worldwide \u2014 including multiple nodes in India.<\/p>\n<h2>When Edge Computing Makes Sense<\/h2>\n<table>\n<thead>\n<tr>\n<th>Use Case<\/th>\n<th>Edge?<\/th>\n<th>Why<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>API responses with user-specific data<\/td>\n<td>\u2705 Yes<\/td>\n<td>Runs close to user, fast<\/td>\n<\/tr>\n<tr>\n<td>Authentication\/JWT validation<\/td>\n<td>\u2705 Yes<\/td>\n<td>No round-trip to origin needed<\/td>\n<\/tr>\n<tr>\n<td>A\/B testing and feature flags<\/td>\n<td>\u2705 Yes<\/td>\n<td>Serve different content without origin<\/td>\n<\/tr>\n<tr>\n<td>Geolocation-based redirects<\/td>\n<td>\u2705 Yes<\/td>\n<td>Cloudflare knows user location natively<\/td>\n<\/tr>\n<tr>\n<td>Rate limiting<\/td>\n<td>\u2705 Yes<\/td>\n<td>Block before reaching your server<\/td>\n<\/tr>\n<tr>\n<td>Image transformation<\/td>\n<td>\u2705 Yes<\/td>\n<td>Resize on the fly at the edge<\/td>\n<\/tr>\n<tr>\n<td>Complex DB queries<\/td>\n<td>\u274c No<\/td>\n<td>DB is still in one location<\/td>\n<\/tr>\n<tr>\n<td>File uploads<\/td>\n<td>\u26a0\ufe0f Partial<\/td>\n<td>Route to R2, process at edge<\/td>\n<\/tr>\n<tr>\n<td>Long-running processes<\/td>\n<td>\u274c No<\/td>\n<td>Workers have 30s CPU limit<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Step 1 \u2014 Setup<\/h2>\n<pre><code>npm install -g wrangler\r\nwrangler login\r\n\r\n# Create a new Worker project\r\nwrangler init my-worker --type javascript\r\ncd my-worker<\/code><\/pre>\n<pre><code>\/\/ wrangler.toml\r\nname = \"softcrony-api\"\r\nmain = \"src\/index.ts\"\r\ncompatibility_date = \"2026-07-01\"\r\ncompatibility_flags = [\"nodejs_compat\"]\r\n\r\n[vars]\r\nENVIRONMENT = \"production\"\r\n\r\n[[kv_namespaces]]\r\nbinding = \"CACHE\"\r\nid = \"your-kv-namespace-id\"\r\n\r\n[[d1_databases]]\r\nbinding = \"DB\"\r\ndatabase_name = \"softcrony-db\"\r\ndatabase_id = \"your-d1-database-id\"<\/code><\/pre>\n<h2>Step 2 \u2014 Basic Worker<\/h2>\n<pre><code>\/\/ src\/index.ts\r\nexport default {\r\n    async fetch(request: Request, env: Env): Promise&lt;Response&gt; {\r\n        const url = new URL(request.url);\r\n\r\n        \/\/ Route based on pathname\r\n        switch (url.pathname) {\r\n            case '\/api\/health':\r\n                return Response.json({ status: 'ok', region: request.cf?.colo });\r\n\r\n            case '\/api\/geo':\r\n                return this.handleGeo(request);\r\n\r\n            default:\r\n                return new Response('Not Found', { status: 404 });\r\n        }\r\n    },\r\n\r\n    handleGeo(request: Request): Response {\r\n        \/\/ Cloudflare provides geolocation data natively\r\n        const cf = request.cf;\r\n\r\n        return Response.json({\r\n            country:  cf?.country,\r\n            city:     cf?.city,\r\n            region:   cf?.region,\r\n            timezone: cf?.timezone,\r\n            isp:      cf?.asOrganization,\r\n            \/\/ Automatically detect Indian users\r\n            isIndia:  cf?.country === 'IN',\r\n        });\r\n    },\r\n};<\/code><\/pre>\n<h2>Step 3 \u2014 Geolocation-Based Content for India<\/h2>\n<pre><code>\/\/ Show prices in INR for Indian users, USD for others\r\nexport default {\r\n    async fetch(request: Request, env: Env): Promise&lt;Response&gt; {\r\n        const country = request.cf?.country;\r\n        const isIndia = country === 'IN';\r\n\r\n        \/\/ Fetch from origin\r\n        const response = await fetch('https:\/\/api.softcrony.com\/products');\r\n        const products = await response.json() as Product[];\r\n\r\n        \/\/ Transform prices based on location\r\n        const localizedProducts = products.map(product =&gt; ({\r\n            ...product,\r\n            price: isIndia\r\n                ? { amount: product.price_inr, currency: 'INR', symbol: '\u20b9' }\r\n                : { amount: product.price_usd, currency: 'USD', symbol: '$' },\r\n            \/\/ Show GST info for Indian users\r\n            tax: isIndia ? { rate: 18, label: 'GST 18%' } : null,\r\n        }));\r\n\r\n        return Response.json(localizedProducts, {\r\n            headers: {\r\n                'Cache-Control': 'public, max-age=300',\r\n                'X-Served-From': request.cf?.colo ?? 'unknown',\r\n                'X-User-Country': country ?? 'unknown',\r\n            },\r\n        });\r\n    },\r\n};<\/code><\/pre>\n<h2>Step 4 \u2014 Rate Limiting at the Edge<\/h2>\n<pre><code>\/\/ Rate limit before request hits your Laravel server\r\nexport default {\r\n    async fetch(request: Request, env: Env): Promise&lt;Response&gt; {\r\n        const ip = request.headers.get('CF-Connecting-IP') ?? 'unknown';\r\n        const key = `rate_limit:${ip}`;\r\n\r\n        \/\/ Check rate limit from KV\r\n        const requests = parseInt(await env.CACHE.get(key) ?? '0');\r\n\r\n        if (requests &gt;= 100) {\r\n            return new Response('Rate limit exceeded', {\r\n                status: 429,\r\n                headers: {\r\n                    'Retry-After': '60',\r\n                    'X-RateLimit-Limit': '100',\r\n                    'X-RateLimit-Remaining': '0',\r\n                },\r\n            });\r\n        }\r\n\r\n        \/\/ Increment counter\r\n        await env.CACHE.put(key, String(requests + 1), {\r\n            expirationTtl: 60 \/\/ Reset after 60 seconds\r\n        });\r\n\r\n        \/\/ Pass to origin\r\n        const response = await fetch(request);\r\n\r\n        return new Response(response.body, {\r\n            ...response,\r\n            headers: {\r\n                ...Object.fromEntries(response.headers),\r\n                'X-RateLimit-Limit': '100',\r\n                'X-RateLimit-Remaining': String(99 - requests),\r\n            },\r\n        });\r\n    },\r\n};<\/code><\/pre>\n<h2>Step 5 \u2014 JWT Authentication at Edge<\/h2>\n<pre><code>import { jwtVerify } from 'jose';\r\n\r\nexport default {\r\n    async fetch(request: Request, env: Env): Promise&lt;Response&gt; {\r\n        \/\/ Only protect API routes\r\n        const url = new URL(request.url);\r\n        if (!url.pathname.startsWith('\/api\/')) {\r\n            return fetch(request);\r\n        }\r\n\r\n        \/\/ Skip auth for public routes\r\n        const publicRoutes = ['\/api\/login', '\/api\/register', '\/api\/health'];\r\n        if (publicRoutes.includes(url.pathname)) {\r\n            return fetch(request);\r\n        }\r\n\r\n        \/\/ Validate JWT at edge \u2014 before hitting Laravel\r\n        const authHeader = request.headers.get('Authorization');\r\n        if (!authHeader?.startsWith('Bearer ')) {\r\n            return Response.json({ error: 'Unauthorized' }, { status: 401 });\r\n        }\r\n\r\n        const token = authHeader.slice(7);\r\n\r\n        try {\r\n            const secret = new TextEncoder().encode(env.JWT_SECRET);\r\n            const { payload } = await jwtVerify(token, secret);\r\n\r\n            \/\/ Add user info to headers for Laravel\r\n            const modifiedRequest = new Request(request, {\r\n                headers: {\r\n                    ...Object.fromEntries(request.headers),\r\n                    'X-User-Id':    String(payload.sub),\r\n                    'X-User-Email': String(payload.email),\r\n                    'X-Tenant-Id':  String(payload.tenant_id),\r\n                },\r\n            });\r\n\r\n            return fetch(modifiedRequest);\r\n\r\n        } catch {\r\n            return Response.json({ error: 'Invalid token' }, { status: 401 });\r\n        }\r\n    },\r\n};<\/code><\/pre>\n<h2>Step 6 \u2014 Cloudflare D1 (Edge Database)<\/h2>\n<p>D1 is Cloudflare&#8217;s SQLite-based edge database \u2014 query data without leaving the edge network:<\/p>\n<pre><code>\/\/ Create D1 database\r\nwrangler d1 create softcrony-db\r\n\r\n\/\/ Apply schema\r\nwrangler d1 execute softcrony-db --file=.\/schema.sql<\/code><\/pre>\n<pre><code>\/\/ schema.sql\r\nCREATE TABLE products (\r\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\r\n    name TEXT NOT NULL,\r\n    price_inr INTEGER NOT NULL,\r\n    price_usd INTEGER NOT NULL,\r\n    status TEXT DEFAULT 'active',\r\n    created_at TEXT DEFAULT (datetime('now'))\r\n);<\/code><\/pre>\n<pre><code>\/\/ Query D1 from Worker\r\nexport default {\r\n    async fetch(request: Request, env: Env): Promise&lt;Response&gt; {\r\n        const { results } = await env.DB.prepare(\r\n            'SELECT * FROM products WHERE status = ? ORDER BY created_at DESC LIMIT 20'\r\n        )\r\n        .bind('active')\r\n        .all();\r\n\r\n        return Response.json(results);\r\n    },\r\n};<\/code><\/pre>\n<h2>Step 7 \u2014 Deploy<\/h2>\n<pre><code># Deploy to production\r\nwrangler deploy\r\n\r\n# Test locally first\r\nwrangler dev\r\n\r\n# View logs in real time\r\nwrangler tail<\/code><\/pre>\n<h2>Performance Impact for Indian Users<\/h2>\n<p>Real numbers from a client project \u2014 a product listing API moved from a DigitalOcean server in Singapore to Cloudflare Workers:<\/p>\n<table>\n<thead>\n<tr>\n<th>Location<\/th>\n<th>Before (Singapore)<\/th>\n<th>After (Edge)<\/th>\n<th>Improvement<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Mumbai<\/td>\n<td>180ms<\/td>\n<td>18ms<\/td>\n<td>90% faster<\/td>\n<\/tr>\n<tr>\n<td>Delhi<\/td>\n<td>210ms<\/td>\n<td>22ms<\/td>\n<td>90% faster<\/td>\n<\/tr>\n<tr>\n<td>Jabalpur<\/td>\n<td>240ms<\/td>\n<td>25ms<\/td>\n<td>90% faster<\/td>\n<\/tr>\n<tr>\n<td>Chennai<\/td>\n<td>160ms<\/td>\n<td>15ms<\/td>\n<td>91% faster<\/td>\n<\/tr>\n<tr>\n<td>Kolkata<\/td>\n<td>230ms<\/td>\n<td>28ms<\/td>\n<td>88% faster<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For the right use cases \u2014 API responses, authentication, rate limiting, geolocation \u2014 edge computing delivers 10x latency improvements for Indian users. This directly impacts conversion rates and user experience on mobile networks.<\/p>\n<p>If you want to implement Cloudflare Workers for your application or need edge computing architecture for an Indian-market product, <a href=\"https:\/\/softcrony.com\/contact\/\">our team at Softcrony can design and implement it<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cloudflare Workers lets you run JavaScript at the network edge \u2014 in data centers physically close to your users, rather than in a central server. For Indian users, this means the difference between 400ms response times from a US server and 20ms from Cloudflare&#8217;s Mumbai or Chennai edge nodes. This guide covers what Cloudflare Workers [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":118,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[108,53,109,20,50,35],"class_list":["post-116","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-cloudflare-workers","tag-devops","tag-edge-computing","tag-india","tag-javascript","tag-performance"],"_links":{"self":[{"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/posts\/116","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/comments?post=116"}],"version-history":[{"count":3,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/posts\/116\/revisions"}],"predecessor-version":[{"id":129,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/posts\/116\/revisions\/129"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/media\/118"}],"wp:attachment":[{"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/media?parent=116"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/categories?post=116"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/softcrony.com\/blog\/wp-json\/wp\/v2\/tags?post=116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}