All posts

2026-08-16

· Dylan Yu
Cloudflare D1SQLiteedgelocal-first

Managing Cloudflare D1 From Your Desktop (Without the Dashboard)

Cloudflare D1 is SQLite at the edge, but the web dashboard is slow for daily work. Here's how to manage D1 databases locally — query, browse, and edit from a desktop app with zero cloud round-trips.

I've been using Cloudflare D1 for a few side projects and one production app for the better part of a year now. And every time I need to actually look at my data — really look at it, not just run a one-off query and squint at the JSON — I end up frustrated. The web dashboard is fine when you're setting up a database for the first time. It is not fine when you're debugging a schema migration at 11pm and you just want to page through 200 rows without waiting two seconds for each page load.

Here's the thing that always gets me: D1 is SQLite. It's literally SQLite. The whole pitch is that your data lives in a SQLite file replicated to Cloudflare's edge locations. So why am I treating it like some exotic cloud database that requires a web browser and a prayer?

This post is the guide I wish I'd had six months ago. I'm going to walk through what D1 actually is, why the dashboard sucks for daily work, and the three real ways to manage a D1 database locally — including the one I actually use now.

What Cloudflare D1 Actually Is

Let's get the architecture straight, because it matters for how you work with D1.

D1 is Cloudflare's serverless SQLite database. The storage layer is SQLite — the actual file format, the actual query engine, the actual B-tree storage. When you create a D1 database, Cloudflare provisions a SQLite database file and replicates it across their edge network. When a Worker runs a query, it executes against the nearest replica of that SQLite file.

The compute layer is Workers. You don't connect to D1 the way you'd connect to Postgres with a TCP connection string. Instead, you bind the D1 database to your Worker, and inside the Worker you call methods like env.DB.prepare("SELECT * FROM users").all(). The Worker runs at the edge, close to the user, and the D1 replica is right there too.

For ad-hoc queries outside of Workers, Cloudflare gives you two paths:

  1. Wrangler CLIwrangler d1 execute and wrangler d1 query run queries from your terminal against the D1 API.
  2. D1 REST API — an HTTP endpoint that accepts SQL and returns JSON. You can hit it from anything that speaks HTTP.

Both of these go through Cloudflare's API, not directly to the SQLite file. There's no way to get a raw SQLite file connection to a production D1 database — that's the tradeoff of serverless. But the query semantics are SQLite semantics. If you know SQLite, you know D1.

This is the key insight that should shape your tooling choices: D1 is SQLite accessed over HTTP. That means any tool that can speak to D1's REST API can give you a SQLite-like experience, and any SQLite knowledge you have transfers directly.

The Problem With the Web Dashboard

Cloudflare has a web dashboard for D1 in the Cloudflare admin panel. You log in, navigate to your database, and you get a query box and a results table. It works. I'm not going to pretend it doesn't exist. But for daily database work — the kind of thing you do when you're building or maintaining an app — it has real problems.

Every query is a network round-trip. You type a query, hit run, and wait for the request to hit Cloudflare's API, execute, and come back. On a good connection that's 300-500ms. On hotel wifi it's longer. When you're exploring data — running a query, looking at the result, tweaking the query, running it again — that latency adds up fast. I've spent more time waiting for dashboard queries to return than I've spent actually thinking about the data.

There's no real browsing experience. The results table is a basic HTML table. You can't reorder columns by dragging. You can't resize columns. You can't freeze the first column while scrolling horizontally. You can't click a row and see it expanded in a detail view. You can't sort by clicking a column header without writing a new ORDER BY clause. These sound like small things, but they're the difference between "I'm exploring my data" and "I'm fighting my tools."

No views beyond a flat table. If your D1 database has a table of support tickets, you might want to see them as a kanban board grouped by status. If it has product data, you might want a gallery view with images. If it has event data, you might want a dashboard with charts. The dashboard gives you none of this. It's a table, or it's nothing.

No AI integration. I use AI assistants — Claude, Cursor, Windsurf — to help me write and debug SQL. With the web dashboard, there's no way for an AI tool to see my schema or query my data. I have to manually copy schema definitions into the chat, run queries myself, copy results back. It's tedious.

No offline. The dashboard is a web app. No internet, no dashboard. I've been on enough flights and enough trains to know this matters.

Context switching. The dashboard lives in a browser tab alongside 47 other browser tabs. When I'm working on my app in my editor, I have to switch to the browser, find the right tab, navigate back to my database. It's friction.

The dashboard is fine for creating a database, setting up bindings, and running a query once a month. It is not a daily driver. And since D1 is SQLite, you shouldn't have to settle for a web UI that's worse than every desktop SQLite browser made in the last 15 years.

Option 1: Wrangler CLI

The official way to interact with D1 outside of Workers is Wrangler, Cloudflare's CLI tool. If you've deployed Workers, you already have it. If not, install it with npm:

npm install -g wrangler

Authenticate with your Cloudflare account:

wrangler login

Then you can list your D1 databases:

wrangler d1 list

Run a query:

wrangler d1 execute my-database --command "SELECT * FROM users LIMIT 10"

Or run a SQL file:

wrangler d1 execute my-database --file ./migration.sql

There's also an interactive query mode:

wrangler d1 query my-database

This drops you into a REPL where you can type queries and see results.

Wrangler is good for what it's good for: scripts, migrations, CI/CD pipelines, quick one-off queries. I use it for running migrations in deploy scripts. It's reliable, it's scriptable, and it stays out of your way.

Where Wrangler falls short is browsing. The output is formatted text in your terminal. It's fine for SELECT COUNT(*) FROM users. It's miserable for SELECT * FROM users when users has 12 columns and you want to actually read the values. There's no way to page through rows visually, no way to click into a row, no way to edit a value inline. You're in a terminal. Terminals are not great for tabular data.

If your workflow is "run a query, look at a number, move on," Wrangler is perfect. If your workflow is "explore a table, understand the shape of the data, find the weird row that's breaking my app," Wrangler will make you unhappy.

Option 2: D1 REST API

Here's where it gets interesting. D1 exposes a REST API, which means you can query it from anything that can make an HTTP request. That's a much bigger deal than it sounds.

The endpoint format is:

https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{database_id}/query

You authenticate with a Cloudflare API token (create one in the dashboard under My Profile > API Tokens, with D1 permissions).

A curl example:

curl -X POST \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/d1/database/$DATABASE_ID/query" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT * FROM users LIMIT 10"}'

The response is JSON:

{
  "result": [
    {
      "results": [
        { "id": 1, "email": "alice@example.com", "name": "Alice" },
        { "id": 2, "email": "bob@example.com", "name": "Bob" }
      ],
      "success": true,
      "meta": {
        "served_by": "d1-micro",
        "duration": 0.34,
        "changes": 0,
        "last_row_id": 0,
        "rows_read": 2,
        "rows_written": 0
      }
    }
  ],
  "success": true,
  "errors": [],
  "messages": []
}

This is the unlock. Because D1 has a REST API, any HTTP client can query it. That means a desktop app can query it. A script can query it. An AI tool can query it. You're not limited to Wrangler or the web dashboard — you can build or use any interface that speaks HTTP.

The REST API supports everything Wrangler supports: SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, ALTER TABLE, schema introspection via sqlite_master, the works. It's SQLite over HTTP.

The raw API is not a great daily interface on its own — you don't want to write curl commands to browse a table. But it's the foundation that better tools can build on. And that's exactly what I want to show you next.

Option 3: A Local Desktop Admin Panel

This is the option I actually use day-to-day. Instead of querying D1 through a web dashboard, I connect a local desktop app to D1's REST API and get a proper admin panel — the kind of thing SQLite has had for years with tools like DB Browser, but running against my D1 database over the API.

The tool I use is BaseVolt. It's a local-first desktop app for macOS and Windows that gives any database a full admin panel. It supports SQLite, PostgreSQL, MySQL, and Cloudflare D1. I'm going to walk through the D1 workflow because that's what this post is about, but the same app handles the others too.

There are other options in this space — TablePlus supports D1 if you configure it right, and you can always roll your own with the REST API and a HTTP client. I use BaseVolt because it's the one that gives me views (kanban, gallery, dashboards) and has the MCP server for AI integration, which I'll get to. But the general approach — connect a desktop app to D1's REST API — is what matters. Pick the tool that fits your workflow.

Step 1: Get Your D1 API Credentials

You need three things from Cloudflare:

  1. Account ID — find this in the Cloudflare dashboard. It's in the URL when you're logged in, or in the account overview page. It's a hex string.
  2. Database ID — the ID of the specific D1 database you want to connect to. Run wrangler d1 list to see your databases and their IDs, or find it in the dashboard under your D1 database's settings.
  3. API Token — create a token at My Profile > API Tokens. For D1 access, the token needs the "D1 Edit" permission at minimum (or "D1 Read" if you only want read access). Scope it to your account.

Keep these handy. You'll need them in a second.

Step 2: Connect BaseVolt

Open BaseVolt and add a new data source. Choose "Cloudflare D1" as the type. BaseVolt asks for the three credentials above — account ID, database ID, API token. Enter them, hit connect.

BaseVolt constructs the D1 REST endpoint from your account ID and database ID:

https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{database_id}/query

And sends your API token as the bearer auth header. That's it. There's no intermediate server — BaseVolt talks to Cloudflare's API directly from your machine. Your API token is stored locally, not sent to any third-party service.

Once connected, BaseVolt introspects your schema by querying sqlite_master and pulls your table list. You see your tables in the sidebar within a couple seconds.

Step 3: Browse Tables, Run Queries, Build Views

This is where the desktop app earns its keep. Once you're connected, you get:

A proper table browser. Click a table, see its rows in a grid. Columns are resizable and reorderable. Click a column header to sort. Page through results without re-running the query. Click a row to see all its fields in a detail panel. Edit a value inline by double-clicking a cell. This is basic database tooling, but it's night and day compared to the web dashboard.

A SQL editor. A real editor with syntax highlighting, autocomplete for table and column names, and query history. Run a query, see results below. Run the same query with a tweak, see new results. The latency is the D1 API round-trip — same as the dashboard — but the interface doesn't get in your way, so the latency is the only thing you're waiting on, not the UI.

Views. This is the part that sold me. BaseVolt lets you build different views on top of any table:

  • Grid view — the default, a spreadsheet-like table.
  • Gallery view — shows each row as a card, good for data with images or files.
  • Kanban view — groups rows by a status field, good for tickets, tasks, anything with a workflow.
  • Dashboard view — charts and metrics built from your data, good for monitoring.

For my support ticket table in D1, I have a kanban view grouped by status. For my events table, I have a dashboard with a count of events today and a bar chart of events by type. These are views I could never get from the web dashboard. They're just not possible there.

All of this runs locally. The queries go to D1 over the REST API, but the interface — the grid, the kanban board, the charts — is all rendered on your machine. No cloud SaaS rendering your UI.

Step 4: Use the MCP Server for AI-Assisted Schema Work

This is the part that surprised me. BaseVolt has a built-in MCP (Model Context Protocol) server. MCP is the standard that lets AI assistants like Claude, Cursor, and Windsurf connect to external tools. With BaseVolt's MCP server running, your AI assistant can see your database schema and run queries against it.

Here's what this looks like in practice. I'm in Cursor, working on my app. I want to add a new column to my users table. I tell Cursor: "Add a last_login_at column to the users table and update the relevant queries in my Worker code." Cursor, connected to BaseVolt's MCP server, can:

  1. Read my current schema (it sees the users table and all its columns).
  2. Generate the ALTER TABLE migration.
  3. Run it against D1 through the MCP server.
  4. Update my Worker code to reference the new column.

I don't have to copy my schema into the chat. I don't have to run the migration manually and report back. The AI assistant does the whole loop because it has a live connection to my database through BaseVolt.

This works for debugging too. "Why is this user's account showing as inactive?" The AI can query the users table, look at the relevant row, check related tables, and figure it out — all through the MCP connection. It's the kind of thing that would take me ten minutes of manual querying, done in one conversation.

The MCP server runs locally as part of BaseVolt. Your AI assistant connects to it on localhost. No data goes through a cloud service to enable the AI integration — the AI tool talks to BaseVolt, BaseVolt talks to D1, and the only cloud in the loop is Cloudflare itself.

Why Local-First Matters for D1

Here's an objection I've heard: "Your D1 data is already in Cloudflare's cloud. Why does it matter if your database tool is also a cloud SaaS?"

It matters because of what's in between. When you use a cloud-hosted database admin tool — a web SaaS that connects to your D1 database — your data flows through that SaaS's servers. Your queries go from your browser to their server, then to Cloudflare, then back through their server to your browser. That intermediate server sees your SQL, your results, your schema. It's a man-in-the-middle by design.

When you use a local-first desktop app, your queries go from your machine directly to Cloudflare's API. No intermediate server. The only parties that see your data are you and Cloudflare, and Cloudflare already has your data because it's their database.

This isn't just about trust — it's about latency and reliability too. A local app doesn't have a server that can go down. It doesn't have a backend that can be rate-limited or DDoSed. It doesn't have a login system that can lock you out. You open the app, it connects to D1, you work. The only dependency is Cloudflare's API being up, which is the dependency you already have.

Local-first also means offline-capable for the parts that don't need the network. BaseVolt caches your schema and recent query results locally. If I lose internet, I can still look at the schema, review past query results, and plan my next migration. I can't run new queries, but I can think — and a lot of database work is thinking, not querying.

The principle is simple: your data is in the cloud because it needs to be globally accessible. Your tools don't need to be in the cloud, and putting them there buys you nothing but a middleman.

Comparison Table

Here's how the options stack up. These are my honest assessments from using all four.

Wrangler CLID1 REST APIWeb DashboardBaseVolt
Setup time5 min (npm install + login)10 min (create API token)0 min (already in dashboard)5 min (install + enter credentials)
Browsing experiencePoor (terminal text output)None (raw HTTP)Basic (HTML table, no frills)Full (grid, detail view, inline edit)
Query speedFast (direct API call)Fast (direct API call)Slow (round-trip + UI render)Fast (direct API call, local UI)
OfflineNoNoNoPartial (schema + cached results)
AI integrationNoneManual (copy-paste)NoneBuilt-in MCP server
Views/dashboardsNoneNoneNoneGrid, gallery, kanban, dashboard
CostFreeFreeFreeFree tier (2 sources); Pro $99/yr
Best forScripts, migrations, CI/CDCustom integrationsOccasional admin tasksDaily database work

A few notes on this table:

Wrangler and the REST API have the same underlying speed because they both hit the same Cloudflare API. The difference is interface — Wrangler gives you a terminal, the REST API gives you nothing (you build your own interface).

The web dashboard is "slow" not because Cloudflare's API is slow, but because the web app adds rendering overhead on top of every API call. Each page of results requires a round-trip and a full UI re-render.

BaseVolt's query speed is the same as Wrangler's — it's hitting the same API. The difference is that the results render in a local UI that doesn't make you wait for a web page to load around them.

The cost row: Wrangler, the REST API, and the dashboard are all free because they're Cloudflare's own tools. BaseVolt has a free tier that covers up to 2 data sources — so if D1 is your only database, or you have D1 plus one Postgres, you're on the free tier forever. Pro is $99/year and adds cross-device sync, which I use to keep my query history and saved views consistent between my laptop and desktop.

When to Use What

You don't have to pick one and commit. I use all of these depending on what I'm doing. Here's my decision guide:

Use the Wrangler CLI when:

  • You're running a migration in a deploy script.
  • You're in a CI/CD pipeline and need to execute SQL programmatically.
  • You need to run a quick one-off query from the terminal and you already have Wrangler installed.
  • You're creating or deleting databases.

Use the D1 REST API when:

  • You're building a custom integration (a script, a bot, an internal tool).
  • You want to query D1 from a language or environment that doesn't have Wrangler.
  • You're writing your own admin tool and need the raw API.

Use the web dashboard when:

  • You're setting up a new D1 database for the first time.
  • You're configuring Workers bindings.
  • You're checking billing or usage metrics.
  • You're on a machine that isn't yours and can't install anything.

Use a local desktop admin panel (BaseVolt or otherwise) when:

  • You're doing daily database work — browsing tables, exploring data, debugging issues.
  • You want views (kanban, gallery, dashboard) on your D1 data.
  • You want AI-assisted schema management through an MCP server.
  • You're working offline or on a bad connection and want a responsive UI.
  • You're managing D1 alongside other databases (Postgres, MySQL, local SQLite) and want one tool for all of them.

The pattern I've settled into: Wrangler for migrations and scripts, the web dashboard for account-level admin, and BaseVolt for everything else. I probably spend 80% of my D1 time in BaseVolt, 15% in Wrangler, and 5% in the dashboard.

Bottom Line

Cloudflare D1 is SQLite at the edge. That's a great architecture for your app. But the tools Cloudflare gives you for managing it — a web dashboard and a CLI — are built for occasional use, not daily work. If you're in your D1 database every day, you deserve a real interface.

The good news is that D1's REST API means you're not stuck with Cloudflare's tools. Any HTTP client can query your database. And a local-first desktop app like BaseVolt can turn that API into a full admin panel — grid views, kanban boards, dashboards, inline editing, AI integration — all running on your machine, with queries going directly to Cloudflare.

You don't have to take my word for it. The free tier covers two data sources, which is more than enough to try it with D1 and see if it fits your workflow.

Try it at basevolt.app — no signup, no credit card.

If you build things on the edge and want to talk about database tooling, find me on X.

BasevoltBasevolt

Try Basevolt — a free local-first database admin panel for PostgreSQL, MySQL, SQLite, and Cloudflare D1.

Download Basevolt Free