svelte-effect-runtime

Query

Read server data with schemas, typed failures, and client usage.

Use Query when the client needs server data and the operation should not mutate anything. A query is easiest to reason about when identical input can safely return cached or repeated output.

When to use this

Use Query for dashboards, profile data, search results, permissions, and detail pages. Reach for Command or Form when a user action changes state.

Minimal working example

import { Query } from "svelte-effect-runtime/server";
import { Effect, Schema } from "effect";

const UserInput = Schema.Struct({
  id: Schema.String,
});

export const get_user = Query(UserInput, ({ id }) =>
  Effect.succeed({
    id,
    name: "Ada Lovelace",
  }),
);
<script lang="ts" effect>
  import { get_user } from "./user.remote";

  const user = get_user({ id: "42" });
</script>

{#await yield* user}
  <p>Loading user...</p>
{:then value}
  <h2>{value.name}</h2>
{/await}

Realistic variant

Model expected failures as data:

import { Query } from "svelte-effect-runtime/server";
import { Effect, Schema } from "effect";

type UserNotFound = {
  readonly _tag: "UserNotFound";
  id: string;
};

export const get_user = Query(Schema.Struct({ id: Schema.String }), ({ id }) =>
  Effect.fail({ _tag: "UserNotFound", id } satisfies UserNotFound),
);

The client can handle the failure in an await block or inside an Effect pipeline.

Query variants

Use the base Query helper for one read per input. Reach for a variant when the access pattern changes:

Common mistakes

  • Mutating data in a query handler.
  • Accepting unvalidated input because TypeScript already knows the caller.
  • Throwing plain Error for expected business failures.
  • Calling a query repeatedly with unstable object inputs created from noisy state.

On this page