Skip to content

feat: improve remote function caching by sorting object keys#15570

Merged
Rich-Harris merged 15 commits into
mainfrom
elliott/remote-functions-deep-equality
Mar 31, 2026
Merged

feat: improve remote function caching by sorting object keys#15570
Rich-Harris merged 15 commits into
mainfrom
elliott/remote-functions-deep-equality

Conversation

@elliott-with-the-longest-name-on-github
Copy link
Copy Markdown
Contributor

@elliott-with-the-longest-name-on-github elliott-with-the-longest-name-on-github commented Mar 19, 2026

(stacked on #15562)

Closes #14906
Closes #15551

This sorts object keys when creating the remote function payload, meaning objects with the same key-value pairs will match up as cache keys. As a consequence, this disallows Maps, Sets, and custom objects as remote function parameters, as they're extremely difficult to turn into reliable keys. If you really need a map, set, or custom object, you can serialize it as an object (using something like Object.fromEntries(map)) and recreate it on the server.

The only other potentially-unexpected result of this is that if you're relying on the order of your object keys across the network boundary, you'll be surprised to find them changed between the remote function invocation and the server handler. If you for some reason really need to depend on your object's key-value order, you should turn it into an array of entries Object.entries(obj) and then reconstruct it on the server (Object.fromEntries(entries)).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 19, 2026

🦋 Changeset detected

Latest commit: 6606c09

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Minor

Not sure what this means? Click here to learn what changesets are.

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

@svelte-docs-bot
Copy link
Copy Markdown

@Rich-Harris
Copy link
Copy Markdown
Member

I think we can do this more simply by sorting before passing to devalue, rather than doing it in a reducer, given that we're disallowing any values that could contain objects other than arrays and POJOs #15590

@phi-bre
Copy link
Copy Markdown
Contributor

phi-bre commented Mar 23, 2026

This change is awesome for DX, love to see it, but I'm sad to see Map/Set/transport support go away for command where I don't see a valid reason for changing (breaking) the current behavior other than to keep the param restrictions "consistent" across all remote functions.

Something feels off about modifying the command payload in general IMO (expectation to receive the same object shape that you submitted is way higher / wasted CPU cycles for on average larger payloads than query / no caching mechanism that requires the change)

Would be nice to see a distinction between GET- and POST-like remote requests.
I could open a PR if that's of any help.

(also, on a side note, it would be awesome if #15572 .arguments would point to a normalized/ordered view of the parameters instead of the first call to a query, in case that PR will be reopened at some point)

Comment thread documentation/docs/20-core-concepts/60-remote-functions.md Outdated
Comment thread .changeset/social-cups-play.md Outdated
@elliott-with-the-longest-name-on-github elliott-with-the-longest-name-on-github force-pushed the elliott/remote-functions-deep-equality branch from c59aeee to 76284d9 Compare March 24, 2026 18:04
@elliott-with-the-longest-name-on-github elliott-with-the-longest-name-on-github changed the base branch from elliott/rework-overrides to main March 24, 2026 18:04
@elliott-with-the-longest-name-on-github
Copy link
Copy Markdown
Contributor Author

@phi-bre don't worry! I figured out how to keep Map/Set/Custom support. We're also skipping sorting on commands now. RegEx is still disallowed for arguments in all cases, as there's just no way to safely take a regex from the client to the server.

Comment thread packages/kit/src/runtime/shared.js Outdated
Comment thread documentation/docs/20-core-concepts/60-remote-functions.md Outdated
Copy link
Copy Markdown
Member

@Rich-Harris Rich-Harris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggested docs tweak but otherwise LGTM. exceedingly clever solution

Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
@Rich-Harris Rich-Harris merged commit 2aa92af into main Mar 31, 2026
29 checks passed
@Rich-Harris Rich-Harris deleted the elliott/remote-functions-deep-equality branch March 31, 2026 16:37
This was referenced Mar 31, 2026
elliott-with-the-longest-name-on-github pushed a commit that referenced this pull request Apr 3, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @sveltejs/kit@2.56.0

### Minor Changes

- breaking: rework client-driven refreshes
([#15562](#15562))


- breaking: stabilize remote function caching by sorting object keys
([#15570](#15570))


- breaking: add `run()` method to queries, disallow awaiting queries
outside render ([#15533](#15533))


- feat: support TypeScript 6.0
([#15595](#15595))


- breaking: isolate command-triggered query refresh failures per-query
([#15562](#15562))


- feat: use `hydratable` for remote function transport
([#15533](#15533))


- feat: allow `form` fields to specify a default value (`field.as(type,
value)`) ([#15577](#15577))

### Patch Changes

- fix: don't request new data when `.refresh` is called on a query with
no cache entry ([#15533](#15533))


- fix: allow using multiple remote functions within one async derived
([#15561](#15561))


- fix: avoid false-positive overridden Vite `base` setting warning when
setting a `paths.base` in `svelte.config.js`
([#15623](#15623))


- fix: manage queries in their own `$effect.root`
([#15533](#15533))


- fix: avoid `inlineDynamicImports` deprecation warning when building
the service worker with Vite 8
([#15550](#15550))


- fix: correctly escape backticks when precomputing CSS
([#15593](#15593))


- fix: discard obsolete forks before finishing navigation
([#15634](#15634))


- chore: tighten up override implementation
([#15562](#15562))


- fix: ensure the default Svelte 5 `error.svelte` file uses runes mode
([#15609](#15609))


- fix: deduplicate same-cache-key `batch` calls during SSR
([#15533](#15533))


- fix: decrement pending_count when form callback doesn't call submit()
([#15520](#15520))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
ampelectrecuted pushed a commit to amp-mod/aw3 that referenced this pull request Apr 4, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@sveltejs/kit](https://svelte.dev) ([source](https://github.com/sveltejs/kit/tree/HEAD/packages/kit)) | [`2.55.0` → `2.56.1`](https://renovatebot.com/diffs/npm/@sveltejs%2fkit/2.55.0/2.56.1) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@sveltejs%2fkit/2.56.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@sveltejs%2fkit/2.55.0/2.56.1?slim=true) |

---

### Release Notes

<details>
<summary>sveltejs/kit (@&#8203;sveltejs/kit)</summary>

### [`v2.56.1`](https://github.com/sveltejs/kit/blob/HEAD/packages/kit/CHANGELOG.md#2561)

[Compare Source](https://github.com/sveltejs/kit/compare/@sveltejs/kit@2.56.0...@sveltejs/kit@2.56.1)

##### Patch Changes

- chore: update JSDoc ([#&#8203;15640](sveltejs/kit#15640))

### [`v2.56.0`](https://github.com/sveltejs/kit/blob/HEAD/packages/kit/CHANGELOG.md#2560)

[Compare Source](https://github.com/sveltejs/kit/compare/@sveltejs/kit@2.55.0...@sveltejs/kit@2.56.0)

##### Minor Changes

- breaking: rework client-driven refreshes ([#&#8203;15562](sveltejs/kit#15562))

- breaking: stabilize remote function caching by sorting object keys ([#&#8203;15570](sveltejs/kit#15570))

- breaking: add `run()` method to queries, disallow awaiting queries outside render ([#&#8203;15533](sveltejs/kit#15533))

- feat: support TypeScript 6.0 ([#&#8203;15595](sveltejs/kit#15595))

- breaking: isolate command-triggered query refresh failures per-query ([#&#8203;15562](sveltejs/kit#15562))

- feat: use `hydratable` for remote function transport ([#&#8203;15533](sveltejs/kit#15533))

- feat: allow `form` fields to specify a default value (`field.as(type, value)`) ([#&#8203;15577](sveltejs/kit#15577))

##### Patch Changes

- fix: don't request new data when `.refresh` is called on a query with no cache entry ([#&#8203;15533](sveltejs/kit#15533))

- fix: allow using multiple remote functions within one async derived ([#&#8203;15561](sveltejs/kit#15561))

- fix: avoid false-positive overridden Vite `base` setting warning when setting a `paths.base` in `svelte.config.js` ([#&#8203;15623](sveltejs/kit#15623))

- fix: manage queries in their own `$effect.root` ([#&#8203;15533](sveltejs/kit#15533))

- fix: avoid `inlineDynamicImports` deprecation warning when building the service worker with Vite 8 ([#&#8203;15550](sveltejs/kit#15550))

- fix: correctly escape backticks when precomputing CSS ([#&#8203;15593](sveltejs/kit#15593))

- fix: discard obsolete forks before finishing navigation ([#&#8203;15634](sveltejs/kit#15634))

- chore: tighten up override implementation ([#&#8203;15562](sveltejs/kit#15562))

- fix: ensure the default Svelte 5 `error.svelte` file uses runes mode ([#&#8203;15609](sveltejs/kit#15609))

- fix: deduplicate same-cache-key `batch` calls during SSR ([#&#8203;15533](sveltejs/kit#15533))

- fix: decrement pending\_count when form callback doesn't call submit() ([#&#8203;15520](sveltejs/kit#15520))

</details>

---

### Configuration

📅 **Schedule**: (in timezone UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDQuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwNC4xIiwidGFyZ2V0QnJhbmNoIjoiZGV2ZWxvcCIsImxhYmVscyI6WyJLaW5kL0RlcGVuZGVuY2llcyJdfQ==-->

Reviewed-on: https://codeberg.org/ampmod/aw3/pulls/57
Co-authored-by: AmpMod Bot <ampmod-bot@noreply.codeberg.org>
Co-committed-by: AmpMod Bot <ampmod-bot@noreply.codeberg.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants