Farm.js

Migrate from SvelteKit

SvelteKit and Farm both use filesystem routes, nested layouts, server rendering, Vite, and standards-based server APIs. The @farm.js/svelte renderer lets route UI remain in Svelte 5 components. Preserve the route tree and component markup while replacing SvelteKit-specific data, navigation, hooks, environment, and deployment APIs.

Using a coding agent?

Point it at /docs/migrations/sveltekit.md. That version maps every SvelteKit feature to its Farm equivalent and ends with a verification checklist.

Create the Farm shell

Add Farm and its Svelte renderer without removing SvelteKit first:

pnpm add @farm.js/core @farm.js/svelte svelte
pnpm add -D @farm.js/cli

Create the smallest Farm config:

import { defineConfig } from "@farm.js/core";
import { svelte } from "@farm.js/svelte";

export default defineConfig({
  renderer: svelte(),
});

Point the application scripts at Farm when the first route is ready:

{
  "scripts": {
    "dev": "farm dev",
    "build": "farm build",
    "start": "node .farm/.output/server/index.mjs"
  }
}

Map the route tree

SvelteKit and Farm both use bracketed dynamic segments. The main change is replacing SvelteKit's +file convention with Farm's page and route modules.

SvelteKit sourceFarm output
src/routes/+page.sveltesrc/app/page.svelte
src/routes/about/+page.sveltesrc/app/about/page.svelte
src/routes/posts/[id]/+page.sveltesrc/app/posts/[id]/page.svelte
src/routes/docs/[...slug]/+page.sveltesrc/app/docs/[...slug]/page.svelte
src/routes/+layout.sveltesrc/app/layout.svelte
nested +layout.sveltenested src/app/**/layout.svelte
+error.sveltethe nearest error.svelte

SvelteKit route groups such as (app) do not add a URL segment. Recreate their layout intent with Farm route groups or the appropriate nested layout structure, and review advanced layout resets manually.

Create a root layout before moving pages:

<script module lang="ts">
  export const hydrate = true;
</script>

<script lang="ts">
  import type { Snippet } from "svelte";

  let { children }: { children?: Snippet } = $props();
</script>

{@render children?.()}

SvelteKit hydrates every page. Farm hydrates a Svelte route only when it or a layout exports hydrate = true, so the root layout above opts the whole app in.

Keep ordinary Svelte markup, runes, stores, actions, transitions, and scoped styles. Replace SvelteKit imports and conventions inside each component, and move Farm route exports such as metadata and hydrate into <script module lang="ts">. See Svelte Renderer for the complete component conventions.

Move load functions

SvelteKit's sibling +page.ts, +page.server.ts, +layout.ts, and +layout.server.ts modules feed data into pages and layouts. Move each load function according to its responsibility:

SvelteKit behaviorFarm destination
server-only page loadcreateServerQuery, server function, or API route
universal loadtyped API/server query plus a Svelte client consumer
reusable cached readcreateServerQuery with an explicit structured key
layout loadshared server query or typed API route
redirect or 404 from loadredirect() or notFound()
dependency invalidationFarm cache, route, API, or server-query invalidation

Keep private environment variables, database calls, and privileged SDKs on the server.

Convert endpoints and form actions

SvelteKit sourceFarm output
src/routes/api/hello/+server.tssrc/app/api/hello/route.ts
exported GET, POST, or PATCHmatching HTTP method exports
actions in +page.server.tsserver functions or validated API route handlers

Both frameworks use Web Request and Response concepts for endpoints, but review cookies, locals, params, and platform access:

export async function POST(request: Request) {
  const body = await request.json();
  return Response.json({ received: body });
}

Prefer createEndpoint when input needs schema validation and typed client generation. Preserve progressive enhancement intentionally when replacing SvelteKit form actions.

Replace navigation and app state

SvelteKit APIFarm Svelte equivalent
ordinary internal <a> linksordinary <a> elements (full page loads)
goto()createRouter().push() from @farm.js/svelte/bindings
redirect()redirect() from @farm.js/core/navigation
error(404)notFound()
page paramsparams from $props()
URL search valuessearchParams from $props() or browser URL state
$app/state or $app/storesroute props, Svelte runes/stores, or renderer-neutral APIs

Choose the smallest state owner. Do not move server-derived user or tenant data into a global browser store unless it is safe to expose.

Move hooks and locals

Review src/hooks.server.ts, src/hooks.client.ts, and event.locals by lifecycle:

  • move request authentication and request-scoped values into Farm middleware
  • move route-specific guards into nested src/app/**/middleware.ts
  • move global server lifecycle behavior into Farm plugins
  • move browser lifecycle behavior into hydrated Svelte components or Farm client plugin hooks
  • pass safe request data through middleware data and keep secrets in server-only context

Repeat sensitive authorization inside API routes and server functions.

Move environment and deployment config

Replace SvelteKit environment modules and adapters explicitly:

SvelteKit sourceFarm destination
$env/static/privatetyped server environment variables
$env/dynamic/privateserver environment access
$env/static/publictyped public environment variables
svelte.config.js adapterFarm deploy.target or a supported Nitro preset
vite.config.tsFarm's vite field when customization is needed
staticFarm's public asset directory

Never move a private value into public environment configuration just because a client component needs related data. Return a safe derived value from the server instead.

Verify and remove SvelteKit

Run both applications during the transition and compare:

  • static, dynamic, optional, rest, and grouped routes
  • nested layouts, layout resets, errors, and redirects
  • server and universal load behavior
  • form actions and progressive enhancement
  • endpoint status codes, headers, cookies, and response bodies
  • hook order, locals, authentication, and authorization
  • SSR, hydration, and client navigation
  • adapter behavior on the target deployment platform

After the Farm application passes those checks, remove @sveltejs/kit, the SvelteKit adapter, .svelte-kit, and framework-specific configuration. Keep svelte and @farm.js/svelte as application dependencies.

For source behavior, refer to SvelteKit's official routing, loading data, advanced routing, and hooks documentation while auditing the original app.