Setting up

Houdini works out of the box with Svelte 5, both in legacy mode or in runes mode. All you need to do is bump the Houdini version in your package.json.

Using runes

Updating your code to make use of runes is pretty straight-forward. Houdini still makes use of Svelte Stores, so your code will continue to work as normal. Here are some examples of how to use Houdini with svelte runes:

Route queries

If your query is SSR’ed, you need to get the store from the PageData like so:

<script lang="ts">
    import type { PageData } from './$houdini'

    interface Props {
        data: PageData;
    }
    const { data }: Props = $props();
    const { MyProfile } = $derived(data);
</script>

<p>Welcome, {$MyProfile.data?.user.name}!</p>
<script>
    interface Props {
        data: PageData
    }
    /* @type { import('undefined').Props } */
    const { data } = $props()
    const { MyProfile } = $derived(data)
</script>

<p>Welcome, {$MyProfile.data?.user.name}!</p>

Component queries

The only thing that changes with component queries is how your props are coming in to your component:

<script lang="ts">
    import { graphql } from '$houdini';
    import type { UserDetailsVariables } from './$houdini';

    interface Props {
        id: string;
    }
    const { id }: Props = $props();

    export const _UserDetailsVariables: UserDetailsVariables = ({ props }) => {
        return {
            id: props.id
        }
    }

    const store = graphql(`
        query UserDetails($id: ID!) {
            user(id: $id) {
                name
            }
        }
    `);
</script>

<p>{$store.data?.user.name}</p>
<script>
    import { graphql } from '$houdini'
    
    interface Props {
        id: string
    }
    /* @type { import('undefined').Props } */
    const { id } = $props()
    
    /* @type { import('./$houdini').UserDetailsVariables } */
    export const _UserDetailsVariables = ({ props }) => {
        return {
            id: props.id,
        }
    }
    
    const store = graphql(`
        query UserDetails($id: ID!) {
            user(id: $id) {
                name
            }
        }
    `)
</script>

<p>{$store.data?.user.name}</p>

Fragments

Similar to component queries, the only thing that changes with fragments is how you get the fragment from your props:

<script lang="ts">
    import { fragment, graphql, type UserCardFragment } from '$houdini';

    interface Props {
        user: UserCardFragment
    }
    const { user }: Props = $props();

    const data = fragment(
        user,
        graphql(`
            fragment UserCardFragment on User {
                name
                age
            }
        `)
    );
</script>

<p>{$data.name} is {$data.age} years old!</p>
<script>
    import { fragment, graphql, type UserCardFragment } from '$houdini'
    
    interface Props {
        user: UserCardFragment
    }
    /* @type { import('undefined').Props } */
    const { user } = $props()
    
    const data = fragment(
        user,
        graphql(`
            fragment UserCardFragment on User {
                name
                age
            }
        `)
    )
</script>

<p>{$data.name} is {$data.age} years old!</p>

Mutations

Mutations are unchanged, simply use them as before:

<script lang="ts">
    import { graphql } from '$houdini';

    const uncheckItem = graphql(`
        mutation UncheckItem($id: ID!) {
            uncheckItem(item: $id) {
                item {
                    id
                    completed
                }
            }
        }
    `);
</script>

<button onclick={() => uncheckItem.mutate({ id: 'my-item' })}>
    Uncheck Item
</button>
<script>
    import { graphql } from '$houdini'
    
    const uncheckItem = graphql(`
        mutation UncheckItem($id: ID!) {
            uncheckItem(item: $id) {
                item {
                    id
                    completed
                }
            }
        }
    `)
</script>

<button onclick={() => uncheckItem.mutate({ id: 'my-item' })}>
    Uncheck Item
</button>