Skip to content

Basic Usage ​

This guide covers the essential patterns for using inertia-sails in your application.

Creating Pages ​

1. Define an Action ​

Create a Sails action that returns an Inertia response:

js
// api/controllers/dashboard/view-dashboard.js
module.exports = {
  friendlyName: 'View dashboard',

  description: 'Display the dashboard page.',

  exits: {
    success: {
      responseType: 'inertia'
    }
  },

  fn: async function () {
    const user = await User.findOne({ id: this.req.session.userId })
    const stats = await Stats.find({ user: user.id })

    return {
      page: 'dashboard/index',
      props: {
        user,
        stats
      }
    }
  }
}

2. Create the Frontend Component ​

Create a Vue or React component at the path specified in page:

Vue (assets/js/pages/dashboard/index.vue)

vue
<script setup>
defineProps({
  user: Object,
  stats: Array
})
</script>

<template>
  <div>
    <h1>Welcome, {{ user.fullName }}</h1>
    <div v-for="stat in stats" :key="stat.id">
      {{ stat.name }}: {{ stat.value }}
    </div>
  </div>
</template>

React (assets/js/pages/dashboard/index.jsx)

jsx
export default function Dashboard({ user, stats }) {
  return (
    <div>
      <h1>Welcome, {user.fullName}</h1>
      {stats.map((stat) => (
        <div key={stat.id}>
          {stat.name}: {stat.value}
        </div>
      ))}
    </div>
  )
}

3. Configure the Route ​

Add a route in config/routes.js:

js
module.exports.routes = {
  'GET /dashboard': 'dashboard/view-dashboard'
}

Sharing Data Globally ​

Share data that's needed across all pages:

js
// api/hooks/custom/index.js
module.exports = function defineCustomHook(sails) {
  return {
    routes: {
      before: {
        'GET /*': {
          skipAssets: true,
          fn: async function (req, res, next) {
            // Share authenticated user
            if (req.session.userId) {
              const user = await User.findOne({ id: req.session.userId })
              sails.inertia.share('loggedInUser', user)
            }

            // Share flash messages
            if (req.session.flash) {
              sails.inertia.share('flash', req.session.flash)
              delete req.session.flash
            }

            return next()
          }
        }
      }
    }
  }
}

Form Handling ​

Submit Form ​

vue
<script setup>
import { useForm } from '@inertiajs/vue3'

const form = useForm({
  fullName: '',
  email: ''
})

function submit() {
  form.post('/profile/update')
}
</script>

<template>
  <form @submit.prevent="submit">
    <input v-model="form.fullName" />
    <input v-model="form.email" type="email" />
    <button :disabled="form.processing">Save</button>
  </form>
</template>

Handle Submission ​

js
// api/controllers/profile/update-profile.js
module.exports = {
  inputs: {
    fullName: { type: 'string', required: true },
    email: { type: 'string', isEmail: true, required: true }
  },

  exits: {
    success: { responseType: 'inertiaRedirect' },
    badRequest: { responseType: 'badRequest' }
  },

  fn: async function ({ fullName, email }) {
    await User.updateOne({ id: this.req.session.userId }).set({
      fullName,
      email
    })

    sails.inertia.flash('success', 'Profile updated!')
    return sails.inertia.back('/profile')
  }
}

Use Inertia's Link component for SPA-like navigation:

Vue

vue
<script setup>
import { Link } from '@inertiajs/vue3'
</script>

<template>
  <Link href="/dashboard">Dashboard</Link>
  <Link href="/profile" method="post">Update Profile</Link>
</template>

React

jsx
import { Link } from '@inertiajs/react'

function Nav() {
  return (
    <nav>
      <Link href="/dashboard">Dashboard</Link>
      <Link href="/profile" method="post">
        Update Profile
      </Link>
    </nav>
  )
}

Architecture Note ​

inertia-sails uses AsyncLocalStorage for request-scoped state. This ensures that share(), flash(), and other per-request APIs don't leak data between concurrent requests. This is transparent to your application code but critical for correctness in production.

Next Steps ​

All open source projects are released under the MIT License.