Integrate into an Existing Worker
Use this when you have an existing Cloudflare Worker (typically a Hono app) and want to mount teenybase into it instead of running a separate backend folder. This is the advanced path. For most projects, creating a separate backend folder is simpler.
1. Install
npm install teenybase hono
npm install -D wrangler @cloudflare/workers-types typescript2. Scaffold with teeny init
teeny init -t with-auth -ynpx teeny init -t with-auth -yteeny init creates the missing teenybase files without touching your existing files:
teenybase.tssrc/index.ts(only if it doesn't exist)wrangler.jsoncworker-configuration.d.ts.dev.varsmigrations/
It also patches tsconfig.json so virtual:teenybase resolves correctly.
teeny init does not modify an existing package.json, which is why you install dependencies yourself in step 1.
3. Wire into your existing worker
If src/index.ts already exists, teeny init will not replace it. You need to add teenybase yourself.
Pass your existing Hono app as the second argument to teenyHono():
import { Hono } from 'hono'
import {$Database, $Env, OpenApiExtension, PocketUIExtension, D1Adapter, teenyHono} from 'teenybase/worker'
import config from 'virtual:teenybase'
type Env = $Env & {Bindings: CloudflareBindings}
const app = new Hono<Env>()
// your existing routes
app.get('/healthz', (c) => c.json({ ok: true }))
app.get('/hello', (c) => c.text('Hello from my existing app'))
// add teenybase routes to your app
teenyHono<Env>(async (c) => {
const db = new $Database(c, config, new D1Adapter(c.env.PRIMARY_DB))
db.extensions.push(new OpenApiExtension(db, true))
db.extensions.push(new PocketUIExtension(db))
return db
}, app)
export default appYour routes and teenybase's /api/v1/* routes coexist on the same app.
4. Add D1 binding
Add the D1 database binding to wrangler.jsonc:
{
"d1_databases": [
{
"binding": "PRIMARY_DB",
"database_name": "<your-database-name>",
"database_id": "<your-database-id>",
"migrations_dir": "migrations"
}
]
}Regenerate types:
npx wrangler types --env-interface CloudflareBindings5. Run locally
teeny deploy --local
teeny devnpx teeny deploy --local
npx teeny devMounting under a sub-path
If you want teenybase at a custom prefix (e.g. /backend/api/v1/...), use Hono's app.route():
const teenyApp = teenyHono<Env>(async (c) => {
return new $Database(c, config, new D1Adapter(c.env.PRIMARY_DB))
})
const app = new Hono<Env>()
app.get('/', (c) => c.text('Home'))
app.route('/backend', teenyApp) // teenybase at /backend/api/v1/...
export default appFile uploads (R2)
Add the R2 bucket binding to wrangler.jsonc:
{
"r2_buckets": [
{
"binding": "R2_BUCKET",
"bucket_name": "my-app-files"
}
]
}Regenerate types:
npx wrangler types --env-interface CloudflareBindingsPass the bucket as the fourth argument to $Database:
const db = new $Database(c, config, new D1Adapter(c.env.PRIMARY_DB), c.env.R2_BUCKET)Deploy
cp .dev.vars .prod.varsteeny deploy --remote
teeny statusnpx teeny deploy --remote
npx teeny statusWhere code should live
teenybase.ts= schema, rules, auth, actions, email configsrc/index.ts= worker wiring, extensions, custom Hono routes, R2 binding
Do not put app routes into teenybase.ts.