Skip to content
intermediate Phase 11 · HTTP Clients and Data Fetching

Async setup and Suspense

Await data directly in setup while Suspense shows a fallback.

45m
0 problems
Topic Progress 0%

Async Setup and Suspense: Core Concepts

Async setup changes when a component can render

An async setup function can await data before the component's setup result is ready. This is useful when a view cannot render meaningfully without a required resource. In Vue, a parent Suspense boundary can display a fallback while an async component or async setup dependency resolves. The boundary coordinates rendering; it does not automatically define the application's loading, error, retry, or cache policy.

Use Suspense when delaying the subtree until required dependencies resolve creates a better experience than rendering partial state. For data that can appear progressively, explicit pending state inside the component may be clearer. A skeleton at the whole-page boundary can hide usable content and make navigation feel blocked. Decide whether the user can interact with the shell while the page data loads.

Define the boundary and fallback

Suspense wraps a single default content branch and a fallback branch. While a dependency is pending, Vue renders the fallback. When it resolves, the default subtree appears. Nesting boundaries can provide local fallbacks for independent regions, but too many layers create confusing loading transitions. Group dependencies by user-visible task, not by component count.

Suspense is an experimental or evolving area across Vue versions and integrations; verify behavior against the project's installed version and SSR framework. Async components created with defineAsyncComponent and async setup components have different loading/error configuration options. Use the appropriate mechanism for code loading versus data loading, and avoid assuming the same error path handles both.

Handle errors and cancellation

An async setup rejection should be handled by an error boundary or application error handler. The Suspense fallback is for pending work, not a complete error UI. Provide a recoverable error state with retry where safe, and distinguish a missing resource from a network outage. A retry should not duplicate a non-idempotent write that might already have completed.

If navigation changes while setup work is pending, decide whether the router cancels, waits, or allows the old request to finish. Use AbortController or a request identity so stale results do not populate a new route. Keep error and loading state scoped to the requested resource. An error boundary should include enough context for diagnosis without exposing secrets or raw server responses.

Lifecycle and rendering environments

During SSR, async setup may run on the server as part of rendering. Browser-only APIs and DOM access must wait for client lifecycle hooks. Server data fetching should be request-scoped and must not put user-specific values in module-level singletons. Hydration should reuse or safely refetch data according to the framework's mechanism; otherwise users may see duplicate requests or mismatched markup.

Suspense does not make arbitrary asynchronous work reactive. Awaited setup dependencies resolve a render boundary, while later refreshes or parameter changes still need a watcher, query library, or explicit state machine. If an async dependency changes after the boundary resolves, determine how the component represents refetching and stale data. The boundary may show fallback again depending on the subtree and version; test the intended UX.

Choose the right loading model

Use async setup and Suspense for required initial dependencies when a clear boundary is useful. Use explicit refs for background refresh, optional widgets, and operations where the rest of the view should remain available. Use a data-fetching/cache library when requests need caching, deduplication, retries, or invalidation across views. Keep error, retry, and freshness responsibilities explicit whichever model is chosen.

Async Setup and Suspense: Practice

Gate a required profile view

Imagine a profile route that cannot show its main content until permissions and account details are loaded. Wrap the route view in a Suspense boundary and make its async setup await those required resources. The fallback should explain that the page is loading without implying a failure. Keep the application shell, navigation, and unrelated panels outside the boundary so they remain interactive.

If permissions and profile can load independently, consider nested boundaries or explicit local states. A single boundary waits for all dependencies before revealing any default content; this can increase perceived latency. If partial content is safe and useful, render it as each resource becomes available instead of blocking the whole route. Do not expose protected data before authorization resolves.

Add an error and retry path

Create an error boundary above the route component and render a fallback when async setup rejects. Provide a retry action that repeats safe reads and a route back to a stable page. Map HTTP 404, 403, and network timeout into distinct user states. Do not show raw response bodies. Log a correlation id and safe error category for diagnostics.

Test a delayed request, a rejected request, and a request that is superseded by route navigation. Confirm the fallback appears only while the required dependency is pending. Verify an old route's response cannot render under the new URL. If setup work performs a mutation, make it idempotent or move it to an explicit action so retrying render cannot repeat the side effect.

Keep browser work on the client

Run an SSR test for the route and confirm setup does not access window, document, or element refs. Move chart initialization, focus management, and observers to onMounted. If the server fetch is user-specific, use request-scoped credentials and a server-safe API client. Never cache one user's result in a shared module variable.

After hydration, change a route parameter and observe what happens. Async setup may not rerun merely because a reused component's parameter changes. Watch the parameter or use a route data/cache mechanism. Decide whether a background refresh should keep the previous view visible or return to Suspense fallback. Test the transition with a slow response to prevent layout flicker.

Compare with explicit loading state

Implement the same view using pending/data/error refs. The explicit model can show the shell and stale data while refreshing; Suspense can provide a cleaner all-or-nothing initial boundary. Compare keyboard focus, screen-reader announcements, layout stability, and retry behavior. Choose based on user flow and dependency criticality rather than minimizing the number of state variables.

Finally, verify loading and error messages are accessible. Use a status region for progress and an alert or focused error summary for failure as appropriate. Keep the fallback concise, avoid indefinite spinners, and provide a recovery action when the operation can safely retry. Suspense coordinates rendering; the product still owns communication.

If several dependencies are awaited sequentially but do not depend on each other, start them together with Promise.all to reduce total wait. Keep error handling per dependency when the view can recover from one optional failure.

Async Setup and Suspense: Trade-offs and Interviews

A boundary can improve or block the experience

Suspense is useful when a subtree depends on required asynchronous setup and should appear as a coherent unit. It can create a clear fallback and prevent partially initialized content. It can also block useful shell content, delay interaction, and create nested loading states that are hard to understand. Choose the boundary around a meaningful user task and keep independent content available where possible.

Suspense does not replace a data cache, error policy, retry design, or stale-response handling. Async setup is often appropriate for initial data, while explicit state or a query library handles refresh and shared cache. Code-split component loading is a separate concern from fetching records. Make the boundary between code, data, and user interaction explicit.

Consider SSR and repeated navigation

Async setup can run during server rendering. Ensure requests use request-scoped identity and avoid shared mutable state. Browser-only APIs wait until client mount. Hydration and cache integration should prevent duplicate work and mismatched content. A reused route component may not rerun setup when only a parameter changes, so watch the relevant route source or use a router-aware data layer.

An async setup error needs an error boundary or explicit handler. The fallback slot alone does not show a rejection. Retry must be safe, and a failed dependency should not leave the user in an indefinite loading state. Test with a rejected promise, route cancellation, and a server render.

In an interview, explain when a Suspense boundary is valuable, what it does not handle, and how errors and SSR are managed. Compare it with explicit pending/error refs and a query library. Discuss accessibility and whether the shell remains interactive. This shows Suspense is a rendering coordination tool with clear limits.

A route transition introduces another boundary. If async setup blocks navigation, the current page may remain visible until the destination is ready; if the router allows the change first, the destination needs its own fallback. Test browser Back, parameter-only navigation, and a component that is cached by KeepAlive. Do not assume every route visit creates a fresh instance.

Error reporting should preserve the route and dependency context without exposing raw data. A retry should be limited to safe reads and should avoid restarting unrelated dependencies that already succeeded. If one optional panel fails, keep the primary task usable and allow that panel to retry locally. If authorization fails, redirect or show a denied state rather than repeatedly retrying a request that cannot succeed.

For SSR, align server and client data contracts so hydration renders the same initial view. If the server prefetches data, transfer it through the framework's supported serialization boundary and avoid embedding secrets. If the client refetches, use a cache key and freshness policy to avoid a visible duplicate wait. Test both slow-server rendering and client navigation because they exercise different timing paths.

Keep a timeout or abort policy so a dependency that never settles does not leave the boundary in a permanent fallback. Make the recovery visible to users.

Quiz

1. Which statement about Async setup and Suspense is accurate?

Question 1 options

2. When reviewing Async setup and Suspense, which point must hold?

Question 2 options

3. What does a Suspense fallback primarily represent?

Question 3 options

4. What should happen when async setup rejects?

Question 4 options

Flashcards

Question

What is Async setup and Suspense?

Answer

Await data directly in setup while Suspense shows a fallback.

Question

Async setup and Suspense: why it matters

Answer

An async setup function can await promises before the component renders its template.

Question

Async setup and Suspense: key detail

Answer

Suspense wraps async components and shows its fallback slot while they resolve.

Question

Async setup and Suspense: practical note

Answer

Errors thrown during async setup propagate to an on-error-captured hook or error boundary.

Question

What does a Suspense fallback primarily represent?

Answer

Suspense coordinates pending async dependencies; the application still needs error, retry, and data policies.

Revision Notes

Key Takeaways

  • 1. Async setup can await required work before the component becomes ready; Suspense supplies a pending fallback for the wrapped subtree.
  • 2. Suspense coordinates rendering, while the application still owns errors, retries, caching, and stale-response policy.
  • 3. Place boundaries around meaningful user tasks so one slow optional panel does not block the whole page.
  • 4. Keep browser-only APIs in client lifecycle hooks and keep user-specific server data request-scoped.
  • 5. Use explicit state or a query layer when refreshes, shared caching, or stale data should remain visible.

Interview Tips

  • • Explain which dependency makes initial rendering wait and why that boundary helps the user.
  • • Describe the rejection and safe retry path separately from the pending fallback.
  • • Compare Suspense with explicit state for background refresh and optional content.
  • • Mention SSR request isolation, hydration, route changes, and how you prevent stale results.

Cheat Sheet

Async setup and Suspense Cheat Sheet

Phase: HTTP Clients and Data Fetching | Level: intermediate

Key points:

  • An async setup function can await promises before the component renders its template.
  • Suspense wraps async components and shows its fallback slot while they resolve.
  • Errors thrown during async setup propagate to an on-error-captured hook or error boundary.
  • Prefetching in a route guard often avoids the Suspense fallback entirely.

Tags: vue, async, suspense

Continue Learning

Before You Start

  • No prerequisites listed.

Related Reading