diff --git a/.changeset/silver-plums-repeat.md b/.changeset/silver-plums-repeat.md
new file mode 100644
index 00000000..b25ffc46
--- /dev/null
+++ b/.changeset/silver-plums-repeat.md
@@ -0,0 +1,5 @@
+---
+"frog": patch
+---
+
+Prioritized devtools route over dynamic path if it exists.
diff --git a/playground/src/index.tsx b/playground/src/index.tsx
index 647e1752..132a861e 100644
--- a/playground/src/index.tsx
+++ b/playground/src/index.tsx
@@ -221,6 +221,26 @@ export const app = new Frog({
],
})
})
+ .frame('/:dynamic', (c) => {
+ const dynamic = c.req.param('dynamic')
+ return c.res({
+ image: (
+
+ dynamic route {dynamic} should still work with devtools
+
+ ),
+ intents: [],
+ })
+ })
.route('/fonts', fontsApp)
.route('/middleware', middlewareApp)
.route('/neynar', neynarApp)
diff --git a/src/frog-base.tsx b/src/frog-base.tsx
index f4ac23a2..92e94b23 100644
--- a/src/frog-base.tsx
+++ b/src/frog-base.tsx
@@ -274,6 +274,14 @@ export class FrogBase<
if (dev) this.dev = { enabled: true, ...(dev ?? {}) }
this._dev = undefined // this is set `true` by `devtools` helper
+
+ // allow devtools to work with dynamic params off base path
+ this.hono.all('*', async (c, next) => {
+ if (this._dev)
+ for (const { handler, path } of c.req.matchedRoutes)
+ if (path === this._dev) return handler(c, next)
+ await next()
+ })
}
frame: HandlerInterface = (