Structuring Workers Bindings and Routes
Use a single Hono entrypoint (src/index.ts) and separate public/frontend routes from protected API routes.
Route Mount Order
- Mount public frontend routes first (
/,/news,/video/:id, etc). - Mount public auth routes (
/api/auth/login,/api/auth/logout). - Apply JWT middleware to
/api/*. - Mount protected API groups (
/api/news,/api/articles,/api/videos,/api/youtube).
const app = new Hono<Env>();
app.route('/', frontendRoutes);
app.route('/api/auth', authRoutes);
app.use('/api/*', jwtAuth());
app.route('/api/news', newsRoutes);
app.route('/api/articles', articleRoutes);
app.route('/api/videos', videoRoutes);
app.route('/api/youtube', youtubeRoutes);
Bindings Layout
Define all Workers resources in one Env type (D1, R2, KV, browser binding, workflow bindings, secrets).
type Bindings = {
DB: D1Database;
ASSETS_BUCKET: R2Bucket;
NEWS_CACHE: KVNamespace;
BROWSER: Fetcher;
GOOGLE_API_KEY: string;
JWT_SECRET: string;
VIDEO_SELECTION_WORKFLOW: Workflow;
// ...other workflow bindings
};
Scheduled Handler Pattern
Use the scheduled handler for orchestration only:
- Always trigger maintenance workflows (refresh/rescrape).
- Gate expensive workflows (selection) by deterministic JST slots.
const triggerDecision = evaluateVideoSelectionTrigger(new Date(event.scheduledTime));
if (triggerDecision.shouldTrigger) {
await env.VIDEO_SELECTION_WORKFLOW.create({ params: { auto: true, triggerSource: 'scheduled' } });
}
Practical Rules
- Keep page routes public and enforce auth at API boundaries.
- Persist workflow IDs to D1 immediately after
.create()so cancel/status APIs are reliable. - Keep scheduled logic deterministic and timezone-explicit.