Title: [Feature]: File-based routing with typed loaders and actions · Issue #149 · bQuery/bQuery · GitHub
Open Graph Title: [Feature]: File-based routing with typed loaders and actions · Issue #149 · bQuery/bQuery
X Title: [Feature]: File-based routing with typed loaders and actions · Issue #149 · bQuery/bQuery
Description: Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case bQuery's router (Stable) is programmatic only, and the SSR router br...
Open Graph Description: Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case bQuery's router (Stable) is ...
X Description: Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case bQuery's router (Stable)...
Opengraph URL: https://github.com/bQuery/bQuery/issues/149
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[Feature]: File-based routing with typed loaders and actions","articleBody":"**Pre-flight checklist**\n- [x] I searched existing issues and did not find a duplicate request.\n- [x] I explained the problem or use case, not just the desired API.\n\n**Problem or use case**\nbQuery's `router` (Stable) is programmatic only, and the SSR router bridge matches against a hand-built route table (`resolveSSRRoute`/`createSSRRouterContext`) while merely *recognizing* a `meta.loader`. There is **no file-based routing and no route-level data API** comparable to SvelteKit's `+page.(server).ts` `load`/form `actions` or React Router/Remix loaders and actions. This is the biggest structural gap for building real applications: data-coupled routes, nested layouts, and server actions are the backbone of the competing meta-frameworks, and bQuery has the router, SSR, and server pieces but no convention tying them together.\n\n**Proposed solution**\nAdd an **opt-in**, build-tool-agnostic file-route convention plus typed route-level `load` and `action` functions that flow data into views and accept mutations — bridging the existing `router`, `ssr` (the `meta.loader` hook), and `server` modules. Because zero-build is a core goal and a bundled build tool is a non-goal, this must be optional (programmatic routing stays fully supported) and must not ship bQuery's own bundler — a small directory-convention loader plus typed helpers, usable from any bundler or even a simple manifest. Loaders run on server and client navigation; actions post to the server (composing with #132 sessions/CSRF and #140 form actions).\n\n**Possible API or UX shape**\n```ts\n// routes/users/[id]/+page.ts\nimport type { Load, Action } from \"@bquery/bquery/router\";\n\nexport const load: Load = async ({ params, ctx }) =\u003e {\n return { user: await getUser(params.id) }; // typed, available to the view\n};\n\nexport const action: Action = async ({ request, ctx }) =\u003e {\n await updateUser(await request.formData());\n return { ok: true }; // progressive-enhancement target for \u003cform\u003e (#140)\n};\n```\n\n**Alternatives considered**\nKeeping programmatic routing only and documenting manual data-loading patterns — leaves bQuery a layer below SvelteKit/Remix/Nuxt for application structure, which is where adoption decisions are made. Building a full opinionated meta-framework with its own bundler — violates the zero-build and no-bundled-build-tool non-goals; the convention must be optional and bundler-agnostic.\n\n**Relevant area**\n`router`\n\n**Additional context**\nCross-cutting: unblocks the data story for `ssr` (#127) and `server` (#131), and is the natural home for form actions (#140). This is the highest-leverage *capability* ticket for \"real apps\" parity, even though `router` itself is already Stable.\n","author":{"url":"https://github.com/JosunLP","@type":"Person","name":"JosunLP"},"datePublished":"2026-06-26T21:25:59.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/149/bQuery/issues/149"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:5475bce3-31a7-54df-d351-70fa1a00a896 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | C7F6:3FF092:50568B:6D7442:6A4DA837 |
| html-safe-nonce | 9387febfb0ef205e4ccb0387c9ee159712781742847bc1e7a80c4b460c97845c |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDN0Y2OjNGRjA5Mjo1MDU2OEI6NkQ3NDQyOjZBNERBODM3IiwidmlzaXRvcl9pZCI6IjU1NDk0NTMzODg2ODc0NTIyMTUiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 48c22ec65218a5154db27197a0cb35c51efc6c39bd032a02fff8641da4b0b897 |
| hovercard-subject-tag | issue:4755240646 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/bQuery/bQuery/149/issue_layout |
| twitter:image | https://opengraph.githubassets.com/03c17bf777ff576804516a7757b04e19cdbd54a1f2057bee5eab736eec881b7a/bQuery/bQuery/issues/149 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/03c17bf777ff576804516a7757b04e19cdbd54a1f2057bee5eab736eec881b7a/bQuery/bQuery/issues/149 |
| og:image:alt | Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case bQuery's router (Stable) is ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | JosunLP |
| hostname | github.com |
| expected-hostname | github.com |
| None | 06b8a6144231bf3a234f1c2e9993861e07ce98a905912b114aa386c2d7e84b33 |
| turbo-cache-control | no-preview |
| go-import | github.com/bQuery/bQuery git https://github.com/bQuery/bQuery.git |
| octolytics-dimension-user_id | 256381806 |
| octolytics-dimension-user_login | bQuery |
| octolytics-dimension-repository_id | 1139284244 |
| octolytics-dimension-repository_nwo | bQuery/bQuery |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1139284244 |
| octolytics-dimension-repository_network_root_nwo | bQuery/bQuery |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 47723578ce6819210724ef064c858fce6d3115a3 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width