diff --git a/docs/2.guide/3.going-further/1.internals.md b/docs/2.guide/3.going-further/1.internals.md
index e0e60f733d..f63be69e7a 100644
--- a/docs/2.guide/3.going-further/1.internals.md
+++ b/docs/2.guide/3.going-further/1.internals.md
@@ -28,6 +28,8 @@ You can think of it as **Runtime Core**.
This context can be accessed using [`useNuxtApp()`](/docs/api/composables/use-nuxt-app) composable within Nuxt plugins and `
```
+If runtime context is unavailable in your scope, `useNuxtApp` will throw an exception when called. You can use [`tryUseNuxtApp`](#tryusenuxtapp) instead for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception.
+
## Methods
### `provide (name, value)`
@@ -257,3 +259,22 @@ Native async context support works currently in Bun and Node.
::
:read-more{to="/docs/guide/going-further/experimental-features#asynccontext"}
+
+## tryUseNuxtApp
+
+This function works exactly the same as `useNuxtApp`, but returns `null` if context is unavailable instead of throwing an exception.
+
+You can use it for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception.
+
+Example usage:
+
+```ts [composable.ts]
+export function useStandType() {
+ // Always works on the client
+ if (tryUseNuxtApp()) {
+ return useRuntimeConfig().public.STAND_TYPE
+ } else {
+ return process.env.STAND_TYPE
+ }
+}
+```
diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts
index 218e252c50..28468fccba 100644
--- a/packages/nuxt/src/app/nuxt.ts
+++ b/packages/nuxt/src/app/nuxt.ts
@@ -439,8 +439,10 @@ export function callWithNuxt any> (nuxt: NuxtApp |
/*@__NO_SIDE_EFFECTS__*/
/**
* Returns the current Nuxt instance.
+ *
+ * Returns `null` if Nuxt instance is unavailable.
*/
-export function useNuxtApp (): NuxtApp {
+export function tryUseNuxtApp (): NuxtApp | null {
let nuxtAppInstance
if (hasInjectionContext()) {
nuxtAppInstance = getCurrentInstance()?.appContext.app.$nuxt
@@ -448,6 +450,18 @@ export function useNuxtApp (): NuxtApp {
nuxtAppInstance = nuxtAppInstance || nuxtAppCtx.tryUse()
+ return nuxtAppInstance || null
+}
+
+/*@__NO_SIDE_EFFECTS__*/
+/**
+ * Returns the current Nuxt instance.
+ *
+ * Throws an error if Nuxt instance is unavailable.
+ */
+export function useNuxtApp (): NuxtApp {
+ const nuxtAppInstance = tryUseNuxtApp()
+
if (!nuxtAppInstance) {
if (import.meta.dev) {
throw new Error('[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at `https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables`.')
diff --git a/packages/nuxt/src/imports/presets.ts b/packages/nuxt/src/imports/presets.ts
index 4404893b4a..2296d8610b 100644
--- a/packages/nuxt/src/imports/presets.ts
+++ b/packages/nuxt/src/imports/presets.ts
@@ -18,7 +18,7 @@ const granularAppPresets: InlinePreset[] = [
imports: ['defineNuxtLink']
},
{
- imports: ['useNuxtApp', 'defineNuxtPlugin', 'definePayloadPlugin', 'useRuntimeConfig', 'defineAppConfig'],
+ imports: ['useNuxtApp', 'tryUseNuxtApp', 'defineNuxtPlugin', 'definePayloadPlugin', 'useRuntimeConfig', 'defineAppConfig'],
from: '#app/nuxt'
},
{
diff --git a/test/basic.test.ts b/test/basic.test.ts
index 63d904512c..51d284ba4f 100644
--- a/test/basic.test.ts
+++ b/test/basic.test.ts
@@ -2130,6 +2130,12 @@ describe.skipIf(process.env.TEST_CONTEXT !== 'async')('Async context', () => {
})
})
+describe.skipIf(process.env.TEST_CONTEXT === 'async')('Async context', () => {
+ it('should be unavailable', async () => {
+ expect(await $fetch('/async-context')).toContain('"hasApp": false')
+ })
+})
+
describe.skipIf(isWindows)('useAsyncData', () => {
it('works after useNuxtData call', async () => {
const page = await createPage('/useAsyncData/nuxt-data')
diff --git a/test/fixtures/basic/composables/async-context.ts b/test/fixtures/basic/composables/async-context.ts
index 6ebdf88ec7..0b928d1ce9 100644
--- a/test/fixtures/basic/composables/async-context.ts
+++ b/test/fixtures/basic/composables/async-context.ts
@@ -12,7 +12,7 @@ async function fn1 () {
async function fn2 () {
await delay()
- const app = useNuxtApp()
+ const app = tryUseNuxtApp()
return {
hasApp: !!app
}