This guide will walk you through integrating Para SDK with TanStack Start while preserving server-side rendering (SSR) capabilities.

TanStack Start is a full-stack React framework powered by TanStack Router. Para SDK uses styled-components internally which requires client-side only loading to work correctly with SSR.

Prerequisites

Before starting, you’ll need a Para API key which you can obtain from the Para Developer Portal. You can learn to create your account and get your API key from the Developer Portal.

Setup Developer Portal

Installation

Install the Para React SDK and React Query:

npm install @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js

Setting Up Polyfills with TanStack Start

Since TanStack Start uses Vite under the hood, we need to set up polyfills for modules like crypto, buffer, etc. that Para SDK relies on. We only want to run these polyfills on the client, not on the server.

  1. Install the Vite Node Polyfills plugin:
npm install vite-plugin-node-polyfills --save-dev
  1. Configure the polyfills in your app.config.ts:
app.config.ts
import { defineConfig } from "@tanstack/react-start/config";
import tsConfigPaths from "vite-tsconfig-paths";
import { nodePolyfills } from "vite-plugin-node-polyfills";

export default defineConfig({
  tsr: { appDirectory: "src" },

  // Base configuration (applied to both client and server)
  vite: {
    plugins: [tsConfigPaths({ projects: ["./tsconfig.json"] })],
    define: {
      // This helps modules determine the execution environment
      "process.browser": true,
    },
  },

  // Client-specific configuration
  routers: {
    client: {
      vite: {
        // Apply node polyfills only on the client side
        plugins: [nodePolyfills()],
      },
    },
  },
});

Setup Postinstall Script

Add the Para setup script to your package.json:

package.json
{
  "scripts": {
    "postinstall": "npx setup-para"
  }
}

Create a Client-Only Providers Component

Create a providers component using React.lazy and ClientOnly to ensure Para SDK only loads on the client:

src/components/Providers.tsx
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ClientOnly } from "@tanstack/react-router";

const queryClient = new QueryClient();

// Lazy load ParaProvider to avoid SSR issues
const LazyParaProvider = React.lazy(() => 
  import("@getpara/react-sdk").then((mod) => ({ 
    default: mod.ParaProvider 
  }))
);

export default function Providers({ children }: React.PropsWithChildren) {
  return (
    <ClientOnly fallback={null}>
      <QueryClientProvider client={queryClient}>
        <LazyParaProvider 
          paraClientConfig={{ 
            apiKey: import.meta.env.VITE_PARA_API_KEY || "", 
            env: "BETA" as const
          }}
          config={{
            appName: "Your App Name"
          }}
        >
          {children}
        </LazyParaProvider>
      </QueryClientProvider>
    </ClientOnly>
  );
}

Para offers two hosted environments: Environment.BETA (alias Environment.DEVELOPMENT) for testing, and Environment.PROD (alias Environment.PRODUCTION) for live use. Select the environment that matches your current development phase.

Wrap Your App with Providers

Update your root component to wrap your application with the Providers component:

src/routes/__root.tsx
import Providers from "~/components/Providers";
import { Outlet } from "@tanstack/react-router";

export function RootComponent() {
  return (
    <html>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </head>
      <body>
        <Providers>
          <main>
            <Outlet />
          </main>
        </Providers>
      </body>
    </html>
  );
}

You can learn more about the ParaProvider and its definition in the .

Create a Client-Only Connect Component

Create a component that uses Para SDK hooks, ensuring it’s only rendered on the client:

src/components/ParaContainer.tsx
import { useModal, useAccount } from "@getpara/react-sdk";

export function ParaContainer() {
  const { openConnectModal, openWalletModal } = useModal();
  const account = useAccount();

  return (
    <div>
      {account.isConnected && account.embedded.wallets?.length ? (
        <div>
          <p>Connected: {account.embedded.wallets[0].address}</p>
          <button onClick={openWalletModal}>
            Manage Wallet
          </button>
        </div>
      ) : (
        <button onClick={openConnectModal}>
          Connect Wallet
        </button>
      )}
    </div>
  );
}

You can learn more about the useModal and useAccount hooks in the .

Use it in your pages with ClientOnly wrapper:

src/routes/index.tsx
import React from "react";
import { createFileRoute, ClientOnly } from "@tanstack/react-router";
import "@getpara/react-sdk/styles.css";

// Lazy load Para container component 
const LazyParaContainer = React.lazy(() =>
  import("~/components/ParaContainer").then((mod) => ({
    default: mod.ParaContainer,
  }))
);

function Home() {
  return (
    <main className="flex flex-col items-center justify-center min-h-screen gap-6 p-8">
      <h1 className="text-2xl font-bold">Para Modal Example</h1>
      
      <ClientOnly fallback={<p>Loading Para components...</p>}>
        <LazyParaContainer />
      </ClientOnly>
    </main>
  );
}

export const Route = createFileRoute("/")({
  component: Home,
});

Example

TanStack Start Example

Next Steps

Success you’ve set up Para with TanStack Start! Now you can expand your application with wallet connections, account management, and more.