Farm.js

Migrate from Nuxt

Nuxt and FARMJS share Vue, file-based routing, server rendering, API routes, Vite, and Nitro deployment output. FARMJS uses a different application and server contract, but the @farm.js/vue renderer lets route UI remain in Vue Single-File Components. Preserve route URLs and server contracts while replacing Nuxt-specific macros, composables, modules, and runtime behavior.

Manual migration

farm migrate does not detect or rewrite Nuxt projects yet. This guide is the migration checklist for Nuxt applications.

Create the Farm shell

Add FARMJS and the Vue renderer without removing Nuxt first:

pnpm add @farm.js/core @farm.js/vue@beta vue
pnpm add -D @farm.js/cli

Create the smallest Farm config:

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

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

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

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

Map pages and layouts

Nuxt 4 normally keeps pages under app/pages; projects using the earlier layout may use pages at the root. Both map into Farm's src/app.

Nuxt sourceFARMJS output
app/pages/index.vue or pages/index.vuesrc/app/page.vue
app/pages/about.vue or pages/about.vuesrc/app/about/page.vue
app/pages/posts/[id].vuesrc/app/posts/[id]/page.vue
app/pages/docs/[...slug].vuesrc/app/docs/[...slug]/page.vue
app/layouts/default.vue or layouts/default.vuesrc/app/layout.vue
nested Nuxt layoutsnested src/app/**/layout.vue files
error.vuethe nearest error.vue and not-found.vue

Create a root layout before moving pages:

<script setup lang="ts">
defineOptions({ inheritAttrs: false });
</script>

<template>
  <slot />
</template>

Keep ordinary templates, <script setup>, refs, computed values, and scoped styles. Replace Nuxt auto-imports and macros with explicit Vue imports and FARMJS route exports. Use a normal <script lang="ts"> block for named exports such as metadata and hydrate, and add defineOptions({ inheritAttrs: false }) so route props do not fall through to the root DOM element.

See Vue Renderer for the complete SFC conventions.

Replace Nuxt navigation

Nuxt APIFARMJS Vue equivalent
<NuxtLink to="/about"><a href="/about">
navigateTo("/sign-in")redirect("/sign-in") in server code
client navigateTo()assign window.location or use an ordinary anchor
useRoute().paramstyped page props declared with defineProps
useRoute().querytyped page props or URLSearchParams in client code
definePageMeta()named metadata, generateMetadata, and route exports

Keep dynamic segment names stable so existing links and external URLs continue to work.

Move data fetching

Classify every useFetch, useAsyncData, and $fetch call by where it should run:

Nuxt behaviorFARMJS destination
server-rendered page dataserver module called while rendering or an API endpoint
cached reusable readcreateServerQuery with an explicit structured key
browser request to an app endpointgenerated API client or fetch
mutation or privileged server actionserver function behind a validated API route
route guard dataroute middleware

Keep database clients, secrets, and privileged provider SDKs in server-only modules. Validate untrusted params, query values, form data, and API bodies before using them.

Convert server routes

Move Nitro server handlers into Farm API route modules:

Nuxt sourceFarm output
server/api/hello.get.tssrc/app/api/hello/route.ts with GET
server/api/users/[id].patch.tssrc/app/api/users/[id]/route.ts with PATCH
server/routes/health.tsan API route or programmatic Farm route
server/middleware/*.tsFarm middleware or a server plugin

Farm handlers use Web Request and Response objects:

export async function GET() {
  return Response.json({ ok: true });
}

Use createEndpoint when the endpoint needs schema validation and a typed generated client.

Move middleware and plugins

Nuxt route middleware and server middleware do not share one lifecycle, so migrate them by responsibility:

  • move authentication redirects and route gates into src/app/**/middleware.ts
  • move global request behavior into farm.config.ts middleware
  • move reusable server lifecycle behavior into a Farm plugin
  • move provider setup into a Farm integration when it owns routes, middleware, or client context
  • replace Nuxt client plugins with Vue components or FARMJS client plugin hooks

Repeat sensitive authorization in API routes and server functions. A page redirect is not an authorization boundary.

Move runtime configuration

Review nuxt.config.ts, app.config.ts, modules, auto-imports, aliases, and runtimeConfig explicitly:

Nuxt configurationFARMJS destination
private runtimeConfigtyped server environment variables
runtimeConfig.publictyped public environment variables
app metadatapage or layout metadata exports
Vite plugins and aliasesthe vite field in farm.config.ts when still needed
Nuxt modulesFARMJS integrations, plugins, or ordinary packages
auto-imported componentsexplicit Vue component imports

Do not expose a private Nuxt runtime value through Farm's public environment configuration.

Verify and remove Nuxt

Run both applications during the transition and compare:

  • static, dynamic, optional, and catch-all routes
  • layouts, metadata, error states, and redirects
  • server-rendered data and client navigation
  • API status codes, headers, cookies, and response bodies
  • middleware order and authorization
  • image and public asset URLs
  • production output on the target deployment platform

After the FARMJS application passes those checks, remove Nuxt, Nuxt modules, .nuxt, and Nuxt-specific deployment configuration. Keep Vue and @farm.js/vue as application dependencies.

For source behavior, refer to Nuxt's official pages, data fetching, and directory structure documentation while auditing the original app.