Builder supports SSR and SSG out-of-the-box for all components and frameworks.
This means that you can leverage the benefits of SSR (Server-Side Rendering) and SSG (Static Site Generation), such as improved performance, SEO, and initial page load times, without any additional setup.
For more detail on how Builder works, read How Builder Works: a Technical Overview.
Make sure you're using a framework that supports these features (check your framework's documentation) and follow your framework's guidelines for fetching data server-side when integrating Pages or Sections.
React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
import { Builder, builder } from '@builder.io/react';
// import getAsyncProps
import { getAsyncProps } from '@builder.io/utils';
export default function MyPage(props) {
return <BuilderComponent model="page" content={props.content} />
}
export async function getStaticProps(context) {
const content = await builder.get('page', { url: context.resolvedUrl }).promise();
// wait until the data arrives before rendering
await getAsyncProps(content, {
async Products(props) {
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json())
}
}
})
return { props: { content } }
}
If you have React custom components that depend on external data sources and need that data server-side, such as a products API, use Builder's getAsyncProps() utility to fetch any data needed server-side before render.
When using getAsyncProps with the Gen 1 React SDK for SSR or SSG, any data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
To make your data available in the Visual Editor, you can fetch the data on the client side by extracting any logic you're already using in getAsyncProps, and calling that logic on the client-side with the caveat that you should only employ this workaround when editing and revert when editing is complete.
import { useIsPreviewing } from '@builder.io/react';
export function Products(props) {
const [data, setData] = useState(props.data);
const isPreviewingInBuilder = useIsPreviewing();
useEffect(() => {
if (isPreviewingInBuilder) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category, isPreviewingInBuilder]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
import { Content, fetchOneEntry} from '@builder.io/sdk-react';
// import getAsyncProps
import { getAsyncProps } from '@builder.io/utils';
export default function MyPage(props) {
return <Content model="page" content={props.content} />
}
export async function getStaticProps(context) {
const content = await fetchOneEntry({
model: 'page',
apiKey: 'YOUR_API_KEY',
userAttributes: {
urlPath: context.resolvedUrl,
},
});
// wait until the data arrives before rendering
await getAsyncProps(content, {
async Products(props) {
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json())
}
}
})
return { props: { content } }
}
When using getAsyncProps with the Gen 2 React SDK for SSR or SSG, data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
Use the isEditing() or isPreviewing() helper functions check that you are in editing mode and conditionally fetch data on the client side:
import { isEditing, isPreviewing } from '@builder.io/sdk-react';
export function Products(props) {
const [data, setData] = useState(props.data);
useEffect(() => {
if (isEditing() || isPreviewing()) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
// app/page.js
import { BuilderComponent, builder } from '@builder.io/react';
import { getAsyncProps } from '@builder.io/utils';
builder.init(/* Replace with your Public API Key */);
// Async server component for fetching data
export async function Page() {
const apiKey = 'YOUR_API_KEY';
// Fetch the page entry from Builder
const page = await Builder.get('page', {
userAttributes: {
urlPath: '/',
},
});
// Use getAsyncProps for server-side data fetching
await getAsyncProps(page, {
async Products(props) {
const apiRoot = 'https://api.example.com';
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
// If the page doesn't exist, you can handle 404s here
if (!page) {
return <div>404 - Page Not Found</div>;
}
// Render the fetched page content using Content component
return <BuilderComponent model="page" content={page} />;
}
export default Page;
When using getAsyncProps with the Gen 1 React SDK for SSR or SSG, any data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
To make your data available in the Visual Editor, you can fetch the data on the client side by extracting any logic you're already using in getAsyncProps, and calling that logic on the client-side with the caveat that you should only employ this workaround when editing and revert when editing is complete.
import { useIsPreviewing } from '@builder.io/react';
export function Products(props) {
const [data, setData] = useState(props.data);
const isPreviewingInBuilder = useIsPreviewing();
useEffect(() => {
if (isPreviewingInBuilder) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category, isPreviewingInBuilder]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
// app/page.js
import { Content } from '@builder.io/sdk-react';
import { getAsyncProps } from '@builder.io/utils';
// Async server component for fetching data
export async function Page() {
const apiKey = 'YOUR_API_KEY';
const page = await fetchOneEntry({
model: 'page',
apiKey: apiKey,
userAttributes: {
urlPath: '/',
},
});
// Use getAsyncProps for server-side data fetching
await getAsyncProps(page, {
async Products(props) {
const apiRoot = 'https://api.example.com';
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
if (!page) {
return <div>404 - Page Not Found</div>;
}
// Render the fetched page content using Content component
return <Content model="page" content={page} />;
}
export default Page;When using getAsyncProps with the Gen 2 React SDK for SSR or SSG, data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
Use the isEditing() or isPreviewing() helper functions check that you are in editing mode and conditionally fetch data on the client side:
import { isEditing, isPreviewing } from '@builder.io/sdk-react';
export function Products(props) {
const [data, setData] = useState(props.data);
useEffect(() => {
if (isEditing() || isPreviewing()) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
// app/[...slug]/page.tsx
import { Content, fetchOneEntry } from '@builder.io/sdk-react';
import { useLoaderData } from '@remix-run/react';
// Fetch the content for the page
export async function loader({ params }: { params: { slug: string } }) {
const urlPath = `/${params.slug}`;
const content = await fetchOneEntry({
model: 'page',
apiKey: 'YOUR_PUBLIC_API_KEY', // Use your actual Public API Key here
userAttributes: {
urlPath,
},
})
await getAsyncProps(content, {
async Products(props) {
// Replace with your API root
const apiRoot = 'https://api.example.com';
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
return { content };
}
export default function Page() {
const content = useLoaderData();
return <Content content={content} model="page" />
}
When using getAsyncProps with the Gen 2 React SDK for SSR or SSG, data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
Use the isEditing() or isPreviewing() helper functions check that you are in editing mode and conditionally fetch data on the client side:
import { isEditing, isPreviewing } from '@builder.io/sdk-react';
export function Products(props) {
const [data, setData] = useState(props.data);
useEffect(() => {
if (isEditing() || isPreviewing()) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
import { BuilderComponent, builder } from '@builder.io/react';
import { getAsyncProps } from '@builder.io/utils';
import { useLoaderData } from '@remix-run/react';
builder.init(YOUR_PUBLIC_API_KEY); // <-- add your Public API Key here
export const loader = async ({ params }) => {
const page = await builder
.get('page', {
userAttributes: {
urlPath: `/${params['*']}`,
},
})
.toPromise();
await getAsyncProps(page, {
async Products(props) {
// Replace with your API root
const apiRoot = 'https://api.example.com';
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
return page;
};
export default function Page() {
const page = useLoaderData();
return <BuilderComponent model="page" content={page} />;
}When using getAsyncProps with the Gen 1 React SDK for SSR or SSG, any data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
To make your data available in the Visual Editor, you can fetch the data on the client side by extracting any logic you're already using in getAsyncProps, and calling that logic on the client-side with the caveat that you should only employ this workaround when editing and revert when editing is complete.
import { useIsPreviewing } from '@builder.io/react';
export function Products(props) {
const [data, setData] = useState(props.data);
const isPreviewingInBuilder = useIsPreviewing();
useEffect(() => {
if (isPreviewingInBuilder) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category, isPreviewingInBuilder]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
import { Content, fetchOneEntry } from '@builder.io/sdk-react';
import { useLoaderData } from '@shopify/hydrogen';
// Fetch the content for the page
export async function loader({ params }: { params: { slug: string } }) {
const urlPath = `/${params.slug.join('/')}`;
const content = await fetchOneEntry({
model: 'page',
apiKey: 'YOUR_PUBLIC_API_KEY',
userAttributes: {
urlPath,
},
})
await getAsyncProps(content, {
async Products(props) {
// Replace with your API root
const apiRoot = 'https://api.example.com';
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
return { content };
}
export default function Page() {
const content = useLoaderData();
return <Content content={content} model="page" />
}
When using getAsyncProps with the Gen 2 React SDK for SSR or SSG, data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
Use the isEditing() or isPreviewing() helper functions check that you are in editing mode and conditionally fetch data on the client side:
import { isEditing, isPreviewing } from '@builder.io/sdk-react';
export function Products(props) {
const [data, setData] = useState(props.data);
useEffect(() => {
if (isEditing() || isPreviewing()) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
To use getAsyncProps(), call the loader function to fetch the Page content and asynchronously resolve any additional data. When the data is resolved, the loader function returns the content for your Remix component:
import { BuilderComponent, builder } from '@builder.io/react';
import { getAsyncProps } from '@builder.io/utils';
import { useLoaderData } from '@remix-run/react';
builder.init(YOUR_PUBLIC_API_KEY); // <-- add your Public API Key here
export const loader = async ({ params }) => {
const page = await builder
.get('page', {
userAttributes: {
urlPath: `/${params['*']}`,
},
})
.toPromise();
await getAsyncProps(page, {
async Products(props) {
// Replace with your API root
const apiRoot = 'https://api.example.com';
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
return page;
};
export default function Page() {
const page = useLoaderData();
return <BuilderComponent model="page" content={page} />;
}When using getAsyncProps with the Gen 1 React SDK for SSR or SSG, any data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
To make your data available in the Visual Editor, you can fetch the data on the client side by extracting any logic you're already using in getAsyncProps, and calling that logic on the client-side with the caveat that you should only employ this workaround when editing and revert when editing is complete.
import { useIsPreviewing } from '@builder.io/react';
export function Products(props) {
const [data, setData] = useState(props.data);
const isPreviewingInBuilder = useIsPreviewing();
useEffect(() => {
if (isPreviewingInBuilder) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category, isPreviewingInBuilder]);
return <div>{data}</div>;
}SSR works out-of-the-box with Svelte.
For any Vue-based framework, such as Nuxt, SSR works out-of-the-box.
For any Vue-based framework, such as Nuxt, SSR works out-of-the-box.
SSR works out-of-the-box with Qwik.
SSR works out-of-the-box with the Angular Gen 2 SDK.
React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
The Gatsby tooling fetches the required data at build time and passes that data to the component when the browser renders the content.
import * as React from 'react';
import { graphql } from 'gatsby';
import { getAsyncProps } from '@builder.io/utils';
import { BuilderComponent, builder } from '@builder.io/react';
// Pass in your Public API key here
builder.init(YOUR_API_KEY);
const PageTemplate = ({ data }) => {
const pageContent = data.allBuilderModels.page[0]?.content;
await getAsyncProps(pageContent, {
async Products(props) {
const apiRoot = 'https://api.example.com'; // Define your API root
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
return (
<>
<title>Gatsby example with Builder.io</title>
<!-- Your Builder content is here -->
<BuilderComponent name="page" content={pageContent} />
</>
);
};
// Use GraphQL at build time to fetch the page content.
export default PageTemplate;
export const pageQuery = graphql`
query ($path: String!) {
allBuilderModels {
page(target: { urlPath: $path }, limit: 1, options: { cachebust: true }) {
content
}
}
}
`;When using getAsyncProps with the Gen 1 React SDK for SSR or SSG, any data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
To make your data available in the Visual Editor, you can fetch the data on the client side by extracting any logic you're already using in getAsyncProps, and calling that logic on the client-side with the caveat that you should only employ this workaround when editing and revert when editing is complete.
import { useIsPreviewing } from '@builder.io/react';
export function Products(props) {
const [data, setData] = useState(props.data);
const isPreviewingInBuilder = useIsPreviewing();
useEffect(() => {
if (isPreviewingInBuilder) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category, isPreviewingInBuilder]);
return <div>{data}</div>;
}React doesn't support server-side data fetching for custom components. For React custom components that need to fetch data server-side, you must use Builder's getAsyncProps utility.
import React from 'react';
import { graphql } from 'gatsby';
import { BuilderComponent, builder } from '@builder.io/sdk-react';
import { getAsyncProps } from '@builder.io/utils';
// Initialize Builder.io with your public API key
builder.init('YOUR_PUBLIC_API_KEY');
// Gatsby page component
const PageTemplate = async ({ data }) => {
const pageContent = data.allBuilderModels.page[0]?.content; // Fetch initial page content
// Call getAsyncProps immediately after getting pageContent
await getAsyncProps(pageContent, {
Products: async (props) => {
const apiRoot = 'https://api.example.com'; // Define your API root
return {
data: await fetch(`${apiRoot}/products?cat=${props.category}`).then((res) => res.json()),
};
},
});
return (
<>
<title>Gatsby example with Builder.io</title>
{/* Render the Builder component with the updated content */}
<BuilderComponent model="page" content={pageContent} />
</>
);
};
// Gatsby's GraphQL query to fetch page content at build time
export const query = graphql`
query ($path: String!) {
allBuilderModels {
page(target: { urlPath: $path }, limit: 1, options: { cachebust: true }) {
content
}
}
}
`;
export default PageTemplate;
When using getAsyncProps with the Gen 2 React SDK for SSR or SSG, data fetched server-side will not be available in the Builder Visual Editor. Since the Visual Editor renders content client-side, components relying on getAsyncProps need a way to fetch data on the client side during editing.
Use the isEditing() or isPreviewing() helper functions check that you are in editing mode and conditionally fetch data on the client side:
import { isEditing, isPreviewing } from '@builder.io/sdk-react';
export function Products(props) {
const [data, setData] = useState(props.data);
useEffect(() => {
if (isEditing() || isPreviewing()) {
fetch(`${apiRoot}/products?cat=${props.category}`).then(res => res.json()).then((data) => setData(data));
}
}, [props.category]);
return <div>{data}</div>;
}The Angular SDK does not support SSR and SSG with custom components.
Angular's default is client-side rendering, where components and pages are rendered in the browser. This means that Angular's architecture is optimized for dynamic and interactive applications that rely heavily on client-side JavaScript execution.
On the other hand, SSR and SSG require the generation of fully rendered HTML on the server before it's sent to the client. This approach is critical for SEO, performance, and usability, especially for content-rich pages.
If you need to use SSR with your Angular custom components and Builder, there are a couple of workarounds worth considering:
- Using a prerendering tool: Consider leveraging a prerendering tool like prerender.io. This can help generate pre-rendered versions of your custom components so search engines and users receive fully rendered content.
- Using Symbols for your components: To facilitate server-side rendering and static site generation, consider building out your custom components as Symbols. This approach helps with smoother integration with Builder's rendering process.
For more context on Angular and SSR, visit Angular's document SSR with Angular Universal.
// src/CodeBlockComponent.jsx
import * as React from "react";
import SyntaxHighlighter from "react-syntax-highlighter";
import { Builder } from "@builder.io/react";
export const CodeBlockComponent = (props) => (
<SyntaxHighlighter language={props.language}>
{props.code}
</SyntaxHighlighter>
);
Builder.registerComponent(CodeBlockComponent, {
name: "Code Block",
inputs: [
{
name: "code",
type: "string",
defaultValue: "const incr = num => num + 1",
},
{
name: "language",
type: "string",
defaultValue: "javascript",
},
],
});
If published changes don't appear on your live site, it may be due to caching issues rather than a problem with Builder.
Builder publishes content to its API immediately. Delays in displaying changes are typically due to caching at the hosting provider level or within your application's caching strategy.
Work directly with your hosting provider to adjust caching for your deployed application. Some common guides are included below:
For more information on server-side data, refer to the getAsyncProps README.