Skip to content

Flash messages ​

Flash messages let you send one-time data to users after redirects. Unlike regular props, flash data isn't persisted in browser history - when a user clicks the back button, they won't see old flash messages reappear.

Use flash for success notifications, error messages, newly created IDs, or any other temporary values.

Sending flash messages ​

Use sails.inertia.flash() in your action:

js
module.exports = {
  exits: {
    success: {
      responseType: 'redirect'
    }
  },
  fn: async function () {
    await User.updateOne({ id: this.req.session.userId }).set({
      timezone: this.req.body.timezone
    })

    sails.inertia.flash('success', 'Timezone updated successfully')

    return '/settings'
  }
}

Flash with redirects ​

Flash data survives redirects. Set the flash, redirect, and the data appears on the next page:

js
module.exports = {
  exits: {
    success: {
      responseType: 'redirect'
    }
  },
  fn: async function () {
    const project = await Project.create(this.req.body).fetch()

    sails.inertia.flash('success', 'Project created!')
    sails.inertia.flash('highlightId', project.id)

    return '/projects'
  }
}

Flash with render ​

You can also use flash when rendering a page directly:

js
module.exports = {
  exits: {
    success: {
      responseType: 'inertia'
    }
  },
  fn: async function () {
    const projects = await Project.find()

    sails.inertia.flash('toast', {
      type: 'info',
      message: 'Welcome back!'
    })

    return {
      page: 'projects/index',
      props: { projects }
    }
  }
}

Reading flash messages ​

Flash data is available on page.props.flash:

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

const page = usePage()
</script>

<template>
  <div v-if="page.props.flash?.success" class="alert alert-success">
    {{ page.props.flash.success }}
  </div>

  <div v-if="page.props.flash?.error" class="alert alert-error">
    {{ page.props.flash.error }}
  </div>
</template>
jsx
import { usePage } from '@inertiajs/react'

export default function Layout({ children }) {
  const { flash } = usePage().props

  return (
    <>
      {flash?.success && (
        <div className="alert alert-success">{flash.success}</div>
      )}
      {flash?.error && <div className="alert alert-error">{flash.error}</div>}
      {children}
    </>
  )
}
svelte
<script>
  import { page } from '@inertiajs/svelte'
</script>

{#if $page.props.flash?.success}
  <div class="alert alert-success">{$page.props.flash.success}</div>
{/if}

{#if $page.props.flash?.error}
  <div class="alert alert-error">{$page.props.flash.error}</div>
{/if}

Global flash event ​

You can listen for flash data globally using Inertia's event system:

vue
<script setup>
import { router } from '@inertiajs/vue3'
import { onMounted, onUnmounted } from 'vue'

let removeListener

onMounted(() => {
  removeListener = router.on('flash', (event) => {
    if (event.detail.flash.toast) {
      showToast(event.detail.flash.toast)
    }
  })
})

onUnmounted(() => {
  removeListener?.()
})
</script>
jsx
import { router } from '@inertiajs/react'
import { useEffect } from 'react'

export default function Layout({ children }) {
  useEffect(() => {
    return router.on('flash', (event) => {
      if (event.detail.flash.toast) {
        showToast(event.detail.flash.toast)
      }
    })
  }, [])

  return children
}

Real-world examples ​

Toast notifications ​

js
// api/controllers/tasks/create.js
module.exports = {
  exits: {
    success: {
      responseType: 'redirect'
    }
  },
  fn: async function () {
    const task = await Task.create(this.req.body).fetch()

    sails.inertia.flash('toast', {
      type: 'success',
      message: 'Task created successfully'
    })

    return `/tasks/${task.id}`
  }
}

Highlight newly created items ​

js
// api/controllers/projects/create.js
module.exports = {
  exits: {
    success: {
      responseType: 'redirect'
    }
  },
  fn: async function () {
    const project = await Project.create(this.req.body).fetch()

    sails.inertia.flash('highlightId', project.id)

    return '/projects'
  }
}
vue
<script setup>
import { usePage } from '@inertiajs/vue3'

defineProps({ projects: Array })

const highlightId = usePage().props.flash?.highlightId
</script>

<template>
  <div
    v-for="project in projects"
    :key="project.id"
    :class="{ 'bg-yellow-100': project.id === highlightId }"
  >
    {{ project.name }}
  </div>
</template>

Multiple flash values ​

js
sails.inertia.flash('success', 'Project created!')
sails.inertia.flash('highlightId', project.id)
sails.inertia.flash('scrollTo', 'projects-section')

All values are merged into the flash object on the response.

sails.inertia.flash() vs req.flash() ​

The Boring JavaScript Stack provides two flash mechanisms:

MethodUse caseAvailable at
sails.inertia.flash()Inertia appspage.props.flash
req.flash()Server-rendered viewsSession (via sails-flash)

For Inertia apps, always use sails.inertia.flash(). It:

  • Stores flash in the session (survives redirects)
  • Automatically includes flash in page.props.flash
  • Works without passing req (uses AsyncLocalStorage internally)
  • Prevents "phantom" messages when users navigate back

The req.flash() method (from sails-flash) is for traditional server-rendered pages and is not automatically included in Inertia responses.

All open source projects are released under the MIT License.