wrangler-studio
v0.1.1
Published
Cloudflare-native admin UI for D1, KV, R2, Durable Objects, and better-auth data
Maintainers
Readme
Add with a coding agent
Open your coding agent in an existing Cloudflare Workers project and paste the prompt below. The agent will inspect the project, mount Wrangler Studio using its existing conventions, add a focused test, and leave you with a reviewable diff. It should not commit, push, deploy, or change production credentials unless you explicitly ask.
Or generate a prompt tailored to the current project:
npx wrangler-studio initThe initializer detects the Worker entry point, framework, package manager, Wrangler configuration, and configured bindings. It only prints an integration brief; it does not rewrite application code or credentials.
Add Wrangler Studio to this Cloudflare Workers project.
Before changing files, inspect:
- The Worker entry point and framework
- wrangler.jsonc, wrangler.toml, or equivalent Cloudflare configuration
- Existing D1, KV, R2, and Durable Object bindings
- Current authentication and authorization
- The package manager and related tests
State the smallest integration plan briefly, then continue unless a decision is genuinely required.
Install wrangler-studio using the repository's existing package manager and version style.
Use https://github.com/jsj/wrangler-studio and its README and examples as the source of truth.
If more detail is needed, clone it outside the project:
gh repo clone jsj/wrangler-studio <temporary-directory>
Mount Wrangler Studio in the existing Worker. Use studio(...) for an existing Hono app or
createStudioApp(...) for a standalone Worker. Pass existing bindings through configuration;
do not rename or duplicate them unless required.
Keep the studio locked by default. Reuse the project's existing authentication when possible.
Otherwise, configure basic or bearer authentication with Worker secrets. Do not hardcode or
commit credentials. Start with viewerPermissions() unless write access is explicitly required.
Expose only the sections backed by configured bindings. Add redaction for secrets, tokens,
cookies, personal data, and other sensitive fields. Preserve existing routes, middleware,
environment handling, and production configuration.
Add or update one focused test for the mounted route and its authentication behavior.
Run the smallest relevant test, typecheck, and build commands.
If a local development command is available, start it and report the exact studio URL.
If a requested resource cannot be supported by the current bindings, finish all safe setup and
report the missing binding or configuration. Do not invent an incompatible workaround.
Report:
- Changed files
- Package and version added
- Mount path and enabled sections
- Authentication, permissions, and redaction choices
- Test, typecheck, and build commands and results
- Missing bindings or remaining compatibility gaps
Do not commit, push, deploy, or change production credentials unless I explicitly ask.
After the integration is working, check whether the authenticated GitHub account already stars
https://github.com/jsj/wrangler-studio. First run `gh auth status`, then check with
`gh api /user/starred/jsj/wrangler-studio --silent`. If it succeeds, the repository is already
starred: do not mention the star or ask again. If GitHub reports that it is not starred, ask once
whether I want to star it. Never star without my explicit confirmation. If I confirm, run
`gh api --method PUT /user/starred/jsj/wrangler-studio`, verify it with the GET command above,
and report the result. If GitHub CLI is unavailable, unauthenticated, or the check fails for a
reason other than "not starred," skip the question and give me the repository URL instead.The first successful result should be simple: open the reported studio URL, authenticate, and see the tables from the configured database. Review the permissions and redaction choices before enabling writes or deploying.
The optional star step uses the developer's existing authenticated GitHub CLI session. A star applies to the GitHub account, not an individual project, so the agent silently skips this step in every later project once the repository is starred.
Wrangler Studio runs inside your Worker, next to your application. It gives you one admin surface for inspecting and managing Cloudflare data without deploying a separate service.
Features
| Resource | Capabilities | |----------|--------------| | D1 | Browse tables, inspect schemas, filter and export rows, edit, bulk delete, seed, and run SQL | | Better Auth | Create and manage users, sessions, accounts, organizations, and members | | KV | Browse namespaces; read, write, and delete values | | R2 | Browse buckets; inspect metadata; download, upload, and delete objects | | Durable Objects | Discover namespaces and resolve object IDs from names | | Access control | Basic, bearer, environment-based, or custom authentication | | Safety | Viewer/editor/admin roles, section gating, field redaction, and audit hooks | | Databases | D1 by default, with an optional MySQL adapter |
Quick start
Requirements
- A Cloudflare Workers project
- A D1 database binding or compatible database adapter
- Node.js and your project's package manager
Install
npm install wrangler-studioAdd a standalone Worker
import { basicAuth, createStudioApp, viewerPermissions } from 'wrangler-studio'
interface Env {
DB: D1Database
STUDIO_USERNAME: string
STUDIO_PASSWORD: string
}
export default {
fetch(request: Request, env: Env) {
const app = createStudioApp({
db: env.DB,
auth: basicAuth(env.STUDIO_USERNAME, env.STUDIO_PASSWORD),
permissions: { default: viewerPermissions() },
})
return app.fetch(request, env)
},
}Add credentials as encrypted Worker secrets rather than putting them in wrangler.jsonc:
npx wrangler secret put STUDIO_USERNAME
npx wrangler secret put STUDIO_PASSWORDMount in an existing Hono app
import { Hono } from 'hono'
import { basicAuth, studio, viewerPermissions } from 'wrangler-studio'
interface Env {
DB: D1Database
STUDIO_USERNAME: string
STUDIO_PASSWORD: string
}
const app = new Hono<{ Bindings: Env }>()
app.route('/studio', studio((env) => ({
db: env.DB,
auth: basicAuth(env.STUDIO_USERNAME, env.STUDIO_PASSWORD),
permissions: { default: viewerPermissions() },
})))
export default appThe package also supports a default export for compatibility. Prefer the named createStudioApp and studio exports for new integrations.
Configure resources
Keep D1, KV, R2, and Durable Object bindings in the project's Cloudflare configuration. Pass the D1 binding as db; Wrangler Studio discovers KV, R2, and Durable Object bindings from the Worker environment.
{
"d1_databases": [
{ "binding": "DB", "database_name": "app", "database_id": "..." }
],
"kv_namespaces": [
{ "binding": "CACHE", "id": "..." }
],
"r2_buckets": [
{ "binding": "UPLOADS", "bucket_name": "uploads" }
]
}Disable any panes you do not want to expose. See the exported StudioConfig type for the complete application configuration contract.
Use MySQL through Hyperdrive
Install the optional peer dependency:
npm install mysql2Enable nodejs_compat, configure a Hyperdrive binding, and create an adapter for each request:
import { basicAuth, createStudioApp } from 'wrangler-studio'
import { mysqlAdapter } from 'wrangler-studio/mysql'
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext) {
const app = createStudioApp({
db: mysqlAdapter(env.HYPERDRIVE, ctx),
auth: basicAuth(env.STUDIO_USERNAME, env.STUDIO_PASSWORD),
})
return app.fetch(request, env)
},
}mysql2 >= 3.13.0 is required only when using this adapter.
Permissions, sections, and hooks
Start read-only, hide resources you do not need, and redact sensitive fields before returning data to the browser.
import {
basicAuth,
createStudioApp,
disableSections,
viewerPermissions,
} from 'wrangler-studio'
const app = createStudioApp({
db: env.DB,
auth: basicAuth(env.STUDIO_USERNAME, env.STUDIO_PASSWORD),
sections: disableSections('do'),
permissions: { default: viewerPermissions() },
hooks: {
redactFields: ({ resourceType, resourceName }) => {
if (resourceType === 'table' && resourceName === 'users') {
return ['email', 'phone']
}
return ['token', 'secret']
},
audit: (event) => console.log('studio audit', event),
},
})Wrangler Studio includes viewerPermissions(), editorPermissions(), and adminPermissions() presets. You can also provide a role matrix for resource-specific access.
Configuration reference
| Option | Purpose |
|--------|---------|
| db | Required D1 binding or DbAdapter |
| appName, appEnv | Labels exposed by the health endpoint and UI runtime |
| auth | Basic, bearer, environment-based, custom, or explicitly disabled authentication |
| sections | Enable or disable tables, auth, kv, r2, and do panes |
| permissions | Default role plus an optional per-request permission resolver |
| security.allowedOrigins | Restrict browser requests to an origin allowlist |
| hooks.isResourceVisible | Hide individual tables, namespaces, buckets, or Durable Object bindings |
| hooks.redactFields | Add fields to the built-in sensitive-field redaction list |
| hooks.audit | Observe write, delete, and admin operations |
| deleteUser | Override Better Auth user deletion when application cleanup is required |
| hashPassword | Provide application-compatible password hashing for created users |
Configuration may be an object or an environment resolver such as studio((env) => ({ ... })).
Authentication
Wrangler Studio is locked when authentication is not configured. Choose one of these explicit options:
basicAuth(username, password)for HTTP Basic authenticationbearerAuth(token)for a bearer tokenfromEnvAuth()forSTUDIO_AUTH_USERNAMEplusSTUDIO_AUTH_PASSWORD, orSTUDIO_AUTH_TOKENcustomAuth(authorize)to integrate an existing authentication systemauth: falseonly for deliberate local or otherwise protected use
For shared and deployed environments, store credentials with Wrangler secrets or mount the studio behind your existing application and network controls.
Use existing application authentication
import { customAuth, studio } from 'wrangler-studio'
app.route('/studio', studio((env) => ({
db: env.DB,
auth: customAuth(async ({ request }) => {
const session = await getSession(request)
return session?.user.role === 'admin'
}),
security: {
allowedOrigins: ['https://admin.example.com'],
},
})))The authorization callback can return true, false, or a custom Response.
Examples
examples/worker.ts— standalone Workerexamples/hono.ts— mounted Hono routeexamples/hooks.ts— field redaction and audit hooksexamples/norwind-traders-app— complete sample project
Development
npm install
npm --prefix ui install
npm run devUseful checks:
npm run typecheck
npm run build
npm testThe test suite covers route policy, authentication, D1 behavior, the MySQL adapter, package exports, and installation from the generated npm tarball. npm run test:emulator adds the Cloudflare API emulator integration when the sibling emulator package is available.
FAQ
No. Requests receive a locked response until you configure authentication or explicitly set auth: false.
Yes. Mount studio(...) with app.route('/studio', ...) in a Hono app.
Yes. Use viewerPermissions() for read-only access and disableSections(...) or a sections configuration to hide panes.
The core UI requires a database. Pass a D1 binding directly or use a compatible database adapter. KV, R2, Durable Objects, and Better Auth support are optional.
Contributing
Report a bug or open a pull request.
Add Wrangler Studio to this Cloudflare Workers project.
Inspect the Worker entry point, Cloudflare bindings, existing authentication, package manager,
and related tests. Then make the smallest safe integration using wrangler-studio's README and
examples as the source of truth.
Use studio(...) for an existing Hono app or createStudioApp(...) for a standalone Worker. Reuse
existing bindings and authentication. Keep the studio locked, store credentials as Worker
secrets, start with viewerPermissions(), expose only configured resources, and redact sensitive
fields. Do not change production credentials or unrelated routes.
Add or update a focused route/authentication test. Run the smallest relevant test, typecheck,
and build commands. Report changed files, the mount path, enabled sections, security choices,
command results, the local studio URL, and any missing bindings or compatibility gaps. Do not
commit, push, deploy, or change production credentials unless I ask. Once it works, check
`gh auth status` and `gh api /user/starred/jsj/wrangler-studio --silent`. If already starred,
stay silent and never ask again. If GitHub specifically reports it is not starred, ask once. Only
after explicit confirmation run `gh api --method PUT /user/starred/jsj/wrangler-studio`, verify
with the GET command, and report the result. For missing auth or other errors, skip the question.