How to implement SSR/ISR with codegen & data integrations?

I am using Plasmic codegen with PostgreSQL data integration on Vercel. Page loads fast but components show loading states for 10 seconds while fetching from data.plasmic.app client-side.

How can we pre-fetch this data server-side with either SSR or ISR?

Current setup:

  • Next.js deployed on Vercel
  • Plasmic codegen (not loader)
  • PostgreSQL integration (data.plasmic.app queries use opId)
  • Standard generated components with PageParamsProvider

Would accept either:

  • SSR with getServerSideProps
  • ISR with getStaticProps + revalidate: 300

Just need the data included in initial HTML so components render with data immediately. Is this possible with codegen? :crossed_fingers:t2:

Hello @higinio_maycotte
Yes — it’s definitely possible to pre-fetch data with Plasmic codegen so that it appears in the initial HTML render (i.e., no client-side loading delay).

See this answer in another forum post for an example:

2 Likes

(post deleted by author)

Thank you so much Sarah, this was incredibly helpful! Like many others, we had poured through the documentation and it wasn’t clear that this was possible using codegen (even though we knew it HAD to be). As you confirmed, ISR is ABSOLUTELY POSSIBLE WITH CODEGEN! :folded_hands: Your proposed solution elegantly maintains all the benefits of Plasmic’s visual data integrations while giving us the performance we need. This helped us avoid a more complex code component approach (which we will tackle later).

Since we successfully implemented ISR with Plasmic codegen we wanted to share our solution for others facing the same client side loading delays / issues.

The Solution: ISR with Pre-fetched Plasmic Queries

We created a centralized ISR system that pre-fetches Plasmic data at build time. Here’s the high-level approach:

  1. Extract Plasmic queries during build using extractPlasmicQueryData from @plasmicapp/react-web/lib/prepass
  2. Wrap data in PlasmicQueryDataProvider to hydrate components with pre-fetched data
  3. Centralized ISR helpers to make implementation simple across pages

Key Implementation Points:

  • Performance: 10+ second loads → ~3ms (99% improvement!)
  • Simple adoption: Just 3 lines to add ISR to any page
  • Production-ready: 15-minute revalidation with automatic background updates
  • No client-side fetching: All data included in initial HTML

Quick Example:

// Before: 10-second client-side loading
export default function MyPage() {
  return <PlasmicMyPage />; // Shows loading states
}

// After: Instant server-rendered content
import { IsrPageWrapper, createIsrStaticProps } from '../lib/isr';

export default function MyPage(props) {
  return (
    <IsrPageWrapper {...props}>
      <PlasmicMyPage />
    </IsrPageWrapper>
  );
}

export const getStaticProps = createIsrStaticProps('/my-page', PlasmicMyPage);

Hybrid _app.tsx for ISR Support

We modified _app.tsx to create a “fast path” for ISR pages that bypasses heavy client-side initialization during server-side rendering:

// Detect ISR pages using explicit markers
const isIsrPage = Boolean(
  pageProps._isrEnabled ||
  Component.isrEnabled ||
  pageProps.queryCache
);

// Fast path: minimal server-side rendering for ISR pages
if (typeof window === 'undefined' && isIsrPage) {
  return (
    <PlasmicRootProvider>
      <Component {...pageProps} />
    </PlasmicRootProvider>
  );
}

// Regular path: full initialization for client-side and non-ISR pages
// ... existing app logic ...

This hybrid approach ensures ISR pages render quickly during build time without unnecessary session checks or client-side state initialization, while preserving all functionality for interactive pages. The dual-path architecture was crucial for achieving the sub-10ms server render times.

Bonus: Debug Your ISR Pages

Adding a simple prop to ISR pages helps with debugging and monitoring:

// In your page component
function FocusPage(props: FocusProps) {
  // Access ISR build info via props (only in dev/preview)
  if (process.env.NODE_ENV !== 'production' && props.buildId) {
    console.log('ISR Debug:', {
      buildId: props.buildId,
      buildTime: props.buildTimestamp,
      queriesFound: props.queriesFound,
      hasCache: !!props.queryCache
    });
  }
  
  return (
    <IsrPageWrapper {...props}>
      <PlasmicFocusAreas />
    </IsrPageWrapper>
  );
}

The ISR system automatically provides these props during build/regeneration:

  • buildId - Unique identifier for each build
  • buildTimestamp - When the page was generated
  • queriesFound - Number of Plasmic queries pre-fetched
  • queryCache - The actual cached data

This helps verify ISR is working correctly without affecting production performance!

Gotchas We Solved:

  1. SSR-safe expressions: Updated Plasmic expressions like window.getPlasmicSession() to include typeof window !== 'undefined' checks
  2. Build warnings: Fixed “window is not defined” errors in components
  3. Environment detection: Different revalidation times for dev vs production
  4. Fixed “Loading…” displayed during/after hydration: Removed React Suspense boundaries for ISR pages by conditionally rendering children directly when hasIsrData is true, preventing the fallback from appearing during hydration even though all data was already pre-fetched in the HTML
  5. Fixed content flash/duplication during hydration: Resolved hydration mismatch where server rendered ISR content immediately but client initially returned null - solution was to remove typeof window === 'undefined' condition from ISR detection so both server and client use identical render paths when isIsrPage is true, eliminating visual artifacts while preserving all ISR functionality

The system works perfectly with Plasmic’s PostgreSQL integration - all opId queries are pre-fetched and cached. Happy to share more details if helpful for documentation!

Thanks again for your help!

Keywords for search: plasmic SSR ISR SSG codegen getStaticProps getServerSideProps data.plasmic.app extractPlasmicQueryData server side rendering static generation data fetching nextjs vercel build time pre-fetch cache performance PlasmicQueryDataProvider react-web prepass revalidate hydration incremental regeneration

2 Likes