All posts
Blog

Self-Hosting SheetsAPI on Cloudflare Workers

How to deploy your own instance of SheetsAPI on Cloudflare Workers — open source, MIT licensed, and runs on the free tier.

4 min read

SheetsAPI is MIT licensed and the full source is on GitHub. That means you can run your own copy — on your own Cloudflare account, under your own domain, with your own Google OAuth credentials — and never touch the hosted version at all. This guide walks through doing exactly that.

Why bother self-hosting?

The hosted version at sheetsapi.gkit.mreshank.com is free while in beta and works for most use cases. Self-hosting makes sense when:

  • You want data ownership. Your API keys and OAuth tokens live in your Cloudflare KV namespace, not ours. Nobody else's incident affects you.
  • You need a custom domain. api.yourproduct.com instead of a shared subdomain on someone else's infrastructure.
  • You're avoiding vendor lock-in. An MIT license means you can fork, modify, and run indefinitely regardless of what happens to the hosted service.
  • You're already deep in Cloudflare. If your frontend is on Cloudflare Pages and your DNS is there too, keeping the worker on the same account simplifies everything.

For a personal project or internal tool, the Cloudflare free tier is more than enough: 100,000 requests per day at no cost.

Prerequisites

You need three things before starting:

  • A Cloudflare account (free tier is fine)
  • Node.js 18 or later
  • Wrangler, the Cloudflare CLI — installed globally or via npx

Install Wrangler if you don't have it:

npm install -g wrangler

Authenticate it against your Cloudflare account:

wrangler login

This opens a browser window. Authorize it, come back to the terminal, and you're ready.

You also need a Google Cloud project with the Sheets API enabled and an OAuth 2.0 client configured. If you haven't done that yet, Google's own guide covers it in about ten minutes. Note down your Client ID and Client Secret — you'll need them shortly.

Clone the repo and install dependencies

git clone https://github.com/gkit-dev/sheetsapi.git
cd sheetsapi
npm install

The worker itself lives in src/. The entry point is src/index.ts. It handles routing, CORS, Google Sheets API v4 calls, and all authentication — no separate server process, no cold-start container. Cloudflare runs it at the edge.

Configure wrangler.toml

Open wrangler.toml in the project root. You need to fill in two things: your Cloudflare account ID and a KV namespace binding.

Find your account ID in the Cloudflare dashboard — it's in the URL when you're logged in (dash.cloudflare.com/<account-id>/) or under Workers & Pages > Overview.

Create the KV namespace for storing API keys:

wrangler kv namespace create SHEETSAPI_KV

Wrangler prints the namespace ID. Copy it. Your wrangler.toml should then look like this:

name = "sheetsapi"
main = "src/index.ts"
compatibility_date = "2024-01-01"
 
account_id = "your_account_id_here"
 
[[kv_namespaces]]
binding = "SHEETSAPI_KV"
id = "your_kv_namespace_id_here"

The binding name must match exactly — the worker references it as SHEETSAPI_KV in the source.

Set environment secrets

Three secrets need to be stored in Cloudflare's secret store rather than in wrangler.toml (which gets committed to version control):

wrangler secret put GOOGLE_CLIENT_ID
wrangler secret put GOOGLE_CLIENT_SECRET
wrangler secret put ENCRYPTION_KEY

Each command prompts you to paste the value. GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET come from your Google Cloud OAuth client. ENCRYPTION_KEY is used to encrypt API keys before they're written to KV — generate a strong random string for this:

openssl rand -base64 32

Paste the output when Wrangler asks for ENCRYPTION_KEY. Do not reuse this value across environments; if it changes after you've created API keys, those keys will be unreadable.

Deploy

wrangler deploy

Wrangler bundles the TypeScript, uploads it to Cloudflare's edge network, and prints the worker URL:

Uploaded sheetsapi (1.23 sec)
Deployed sheetsapi triggers (0.27 sec)
  https://sheetsapi.<your-subdomain>.workers.dev

That URL is live immediately — no DNS propagation, no waiting. The worker runs in Cloudflare's global network, meaning it executes close to whoever makes the request.

Test the deployment

Smoke-test it with curl. The health endpoint should return a 200:

curl https://sheetsapi.<your-subdomain>.workers.dev/health

Expected response:

{ "status": "ok" }

Then try a real read against a Sheet you own. Grab a userKey from your dashboard (or check the source for how it's derived from your Google account), and:

curl "https://sheetsapi.<your-subdomain>.workers.dev/api/spreadsheets/{userKey}/{sheetName}?limit=5"

If you get back JSON rows, it's working. If you get a 401, you haven't created an API key yet — the worker follows the same opt-in auth model as the hosted version: public by default, locked once you create a key.

Set up a custom domain

In the Cloudflare dashboard, go to Workers & Pages, find your sheetsapi worker, and open the Settings > Domains & Routes tab. Click Add Custom Domain and enter whatever you want — api.yoursite.com works fine.

Cloudflare handles the SSL certificate automatically. If your domain's DNS is managed outside Cloudflare, you'll need to add a CNAME pointing to sheetsapi.<your-subdomain>.workers.dev and wait for it to propagate.

After that, every request to api.yoursite.com routes through the worker. Update any clients to use the new URL and you're done with the hosted version entirely.

Free tier limits and what happens when you hit them

Cloudflare's free Workers tier gives you:

  • 100,000 requests per day
  • 10ms CPU time per invocation (wall-clock time is longer — this is pure compute)
  • KV reads: 100,000/day; KV writes: 1,000/day

For a personal project, an internal dashboard, or a low-traffic public API, 100k requests/day is substantial. A sheet with 50 rows, read every 30 seconds by one user, is roughly 3,000 requests/day — well inside the limit.

Where you'll bump into the ceiling: KV writes. Every time a user creates or rotates an API key, that's a write. If you're building something where many users are generating keys frequently, you'll hit 1,000 writes/day before you hit the request limit. The paid Workers plan ($5/month) removes those constraints.

CPU time at 10ms is rarely a concern for Sheets API calls — the worker does a quick KV lookup and proxies a Google API call. If you add custom logic that does heavy computation per request, profile it.


Self-hosting gives you a SheetsAPI instance that's entirely yours. The MIT license means there's no legal ambiguity about running it, modifying it, or building a product on top of it. The Cloudflare free tier means the infrastructure cost is zero until you scale past it.

For the full source and open issues, see the SheetsAPI repository on GitHub. If you run into a deployment issue specific to your environment, the wrangler.toml configuration and the KV namespace binding are where most problems originate — double-check those first.

Share