Skip to content

feat: include nested query data in responses#15993

Closed
Rich-Harris wants to merge 16 commits into
dedupe-remote-datafrom
queries-in-queries
Closed

feat: include nested query data in responses#15993
Rich-Harris wants to merge 16 commits into
dedupe-remote-datafrom
queries-in-queries

Conversation

@Rich-Harris

@Rich-Harris Rich-Harris commented Jun 9, 2026

Copy link
Copy Markdown
Member

Stacked on #15991. This is an alternative to #15952.

This PR makes queries more composable, consistent, and waterfall-proof, and (WIP, but fingers crossed) it does that while reducing the amount of code and complexity. The idea is this: if query A depends on query B, then the values of both will be included in the payload returned from the server, whether for SSR or client-side navigation. That way, if we end up rendering both queries, we don't need to go back to the server for query B's data.

For SSR this isn't such a big deal: if we're already rendering query B on the server then it will end up in the rendered HTML. But for client-side navigation it's a much bigger win, because we eagerly get the stuff query A depends on.

'Depends on' can be expressed in three different ways:

  • const x = await queryB() causes x to be added to the returned payload. If x is part of query A's return value, it doesn't get serialized twice — instead, both queries hold a reference to the same object whether on the server or the client
  • queryB().refresh() causes query B to be refreshed at the end of the query, much as happens for command and form today. (If the data is already available by the end of the query, no additional work happens)
  • queryB().set(data) causes the value of query B to immediately be set to data, and this is what gets sent back to the browser. This is particularly useful when dealing with databases or APIs, where an outer query may get several rows, and can populate the corresponding inner queries with their data without them needing to make their own calls

As well as making waterfalls less likely, this also increases consistency: if query A is refreshed, query B will automatically be refreshed along with it.

Places where this could be useful:

  • Eagerly loading the first n items in a list the user is navigating to
  • Navigating from a list to a detail page, instantly showing the summary data we already have available while putting more expensive stuff inside a pending boundary
  • Tree views, where recursion/waterfalls are all but unavoidable, and where it's useful to have each node-and-its-children represented as a query so that granular updates can be performed

There is one downside here:

export const getSummary = query(v.string(), async (id) => {
  const data = await getAHugeFatBlobOfStuffWeMostlyDontNeed(id);
  return data.summary;
});

The answer, of course, is don't do that. Or put differently: the documentation would steer people away from that pattern and towards smaller, more composable queries.

(Needless to say, if getAHugeFatBlobOfStuffWeMostlyDontNeed is a normal function and not a query, its return value will not be serialized. You have lots of good ways to design your queries, is what I'm saying.)

TODO:

  • await queryB() doesn't currently do anything for remote requests, because contents of remote.data are ignored in this context unlike remote.refreshes. it only behaves correctly in SSR. queryB().refresh() does work, however
  • for remote requests, the main query value needs to be serialized in the same blob as the refreshes for deduplication to work correctly
  • prolly add a test or two

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: fda1cd8

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@svelte-docs-bot

Copy link
Copy Markdown

@Rich-Harris

Copy link
Copy Markdown
Member Author

closing in favour of #15999

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant